【手搓 Agent 第1关】建立最小 Agent(上):代码前置基础

在 Stage 0 我们完成了 Agent 基础认知与工程选型,现在正式进入实操编码阶段。在第一阶段,我们计划搭建最小的 Agent Loop 完成以下目标:

本篇为 Stage 1 上篇,聚焦搭建 Agent 的底层前置能力:手把手封装 LLM 基础调用接口,实现多轮对话上下文记忆、自定义系统角色提示词,最后掌握强制模型输出标准 JSON 结构化数据的方案。

一、基础对话与结构化输出

1. 用 API 调用大模型进行简单对话

先创建.env环境变量文件。

代码主体

import os
from openai import OpenAI
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# 获取 OpenAI API Key
API_KEY = os.getenv("LLM_API_KEY")
Model_ID = os.getenv("LLM_MODEL_ID")
Base_URL = os.getenv("LLM_BASE_URL")

# 初始化 OpenAI 客户端
client = OpenAI(api_key=API_KEY, base_url=Base_URL)
def generate_response(prompt):
    """
    使用 OpenAI API 生成响应
    :param prompt: 用户输入的提示
    :return: 模型生成的响应
    """
    try:
        response = client.chat.completions.create(
            model=Model_ID,
            messages=[{"role": "user", "content": prompt}]
        )
        return response.choices[0].message.content.strip()
    except Exception as e:
        print(f"Error generating response: {e}")
        return "抱歉,生成响应时发生错误。"

快速测试是否可用

# 示例用法
if __name__ == "__main__":
    user_prompt = "你好,回复我调试成功"
    response = generate_response(user_prompt)
    print("模型响应:", response)

想要手动输入交互对话

# 示例用法
if __name__ == "__main__":
    print("AI对话程序,输入 quit 结束对话")
    while True:
	    user_prompt = input("你:")
	    if user_prompt == "quit":
		    print("对话结束")
		    break
		  response = generate_response(user_prompt)
	    print("AI:", response, "\n")

示例输出

你:你好,我叫阿言  
AI: 很高兴认识你,阿言!今天过得怎么样?有没有什么想和我聊聊的,或者需要我帮忙的吗?😊

你:你还记得我叫什么吗
AI: 你好!每次对话对我来说都是新的开始,所以我暂时无法记住你的名字~不过如果你愿意告诉我,我会很乐意在**当前对话**中称呼你哦!😊 你叫什么名字呢?

此时大模型无法记住上下文,所以我们需要加入上下文模块。

2. 加入上下文功能

为了令大模型能记住上下文,我们需要设置chat_history来存储之前的对话。

代码修改

  1. 初始化 OpenAI 客户端后,加入全局列表存储完整对话历史chat_history = [ ]
  2. 修改generate_response函数定义,每一轮次先在对话历史中加入用户 input:chat_history.append({"role": "user", "content": prompt}),再在 AI 回复后加入 AI 的回复:chat_history.append({"role": "assistant", "content": response.choices[0].message.content.strip()}

完整代码演示

chat_history = [ ]

def generate_response(prompt):
    """
    使用 OpenAI API 生成响应
    :param prompt: 用户输入的提示
    :return: 模型生成的响应
    """
    try:
        chat_history.append({"role": "user", "content": prompt})
        response = client.chat.completions.create(
            model=Model_ID,
            messages=chat_history
        )
        ai_response = response.choices[0].message.content.strip()
        chat_history.append({"role": "assistant", "content": ai_response})
        return ai_response
    except Exception as e:
        print(f"Error generating response: {e}")
        return "抱歉,生成响应时发生错误。"

示例输出

你:你好,我叫阿言
AI: 你好呀,阿言!👋 很高兴认识你~我是你的智能助手。今天有什么想聊的,或者需要我帮忙的地方吗?不管是回答问题、查资料,还是随便聊聊,随时都可以告诉我哦!😊

你:你还记得我叫什么吗?
AI: 当然记得呀,你叫**阿言**!😊咱们刚才才见面的~ 今天过得怎么样?有什么想聊的或者需要我帮忙的吗?

3. 加入系统提示词

Agent 一般都要有一个系统提示词,来规定 AI 的行为模式。可以通过定义系统提示词,让大模型在读取 message 信息时获得系统提示词。这个提示词只需要在一开始(即初始化 OpenAI 客户端后)定义一次,然后将其放入对话历史储存。

代码主体

# 定义系统提示词
system_prompt = {
    "role": "system",
    "content": "你是一个有帮助的AI助手,叫小爱。请根据用户的输入提供有用的信息和建议。"
}
# 全局列表存储完整对话历史,实现上下文
chat_history = [system_prompt]

示例输出

你:你好,我叫阿言,你叫什么名字
AI: 你好呀,阿言!很高兴认识你~👋我叫**小爱**,是你的智能助手。无论是解答疑惑、提供建议,还是日常聊天,我都在这里随时待命哦!今天有什么我可以帮你的吗?😊

4. 结构化输出

为什么希望 LLM 返回 JSON 格式?

优势 具体说明
结构化处理 程序可直接用json.loads()解析,无需复杂正则提取,避免字符串解析错误
数据集成 可直接导入数据库、作为 API 响应或工作流中间数据,无缝对接下游系统
类型安全 明确字段定义与类型,避免数据类型混淆(如数字 vs 字符串)
结果一致性 强制固定字段(如thought+final_answer),消除自由文本的不确定性
智能体适配 完美支持工具调用、多轮对话状态管理等 AI Agent 场景
错误可检测 JSON 格式错误可被程序立即捕获,便于重试或修复

JSON 格式输出的简单方法

  1. 系统提示词修改
"role": "system",
"content": "你是一个专业的数据格式化助手。请严格遵循以下规则:\
1. 仅输出符合 RFC 8259 标准的纯 JSON,无任何多余文字、解释、注释。\
2. 禁止使用 Markdown 代码块、禁止加 ```json 标记。\
3. 字段名称、类型严格按照要求,字符串用双引号,禁止尾随逗号。\
4. 只返回 JSON,不回答任何其他问题。"
  1. 写入函数硬性要求输出格式response_format={"type": "json_object"}

加入位置:

response = client.chat.completions.create(
    model=Model_ID,
    response_format={"type": "json_object"},
    messages=chat_history
)

二、本篇总结 & 下期预告

本篇我们完成了纯大模型对话、上下文管理、结构化输出三大基础能力,但当前模型仅能纯文本回答,没有执行外部操作的能力,还不能称之为真正的 Agent。

下一篇 Stage 1(中),我们将为模型拓展核心实操能力,详解工具规范定义、Schema 配置、工具调用解析与结果回传逻辑,让大模型拥有「动手执行任务」的能力。

posted @ 2026-07-22 13:18  Alkaid2077  阅读(130)  评论(0)    收藏  举报