Skip to content

预计时间

2 周

学习目标

  • 理解 ReAct 循环
  • 掌握 Tool Calling 实操
  • 理解 Planning / Memory / Reflection
  • 能用 LangGraph 搭建 Agent

一、Agent 是什么?

text
普通 LLM:
  用户:"帮我查一下深圳天气,然后决定穿什么"
  LLM:"深圳今天 28 度,建议穿短袖"  ← 它猜的,没真查

Agent:
  用户:"帮我查一下深圳天气,然后决定穿什么"
  Agent → 思考:"我需要先查天气"
  Agent → 调 get_weather("深圳") → 拿到真实数据
  Agent → 思考:"28 度,晴天"
  Agent → 输出:"深圳今天 28 度晴天,建议穿短袖加薄外套"  ← 基于真实数据

一句话

Agent = LLM + 工具 + 循环决策 LLM 是大脑,工具是手脚,循环是不断尝试直到完成任务。


二、ReAct 模式

ReAct = Reasoning(推理)+ Acting(行动),是 Agent 最核心的运作模式。

text
循环:
  Thought → Action → Observation → Thought → Action → ... → Answer

示例:用户问"公司去年利润多少?"

  Thought: 我需要查公司去年的财务数据
  Action: search_knowledge_base("2025 年利润")
  Observation: 找到 3 条记录,其中一条显示"2025 年净利润 5000 万"

  Thought: 找到了,可以直接回答
  Answer: 公司 2025 年净利润为 5000 万元。

如果没找到:
  Thought: 知识库里没有去年的数据,试试查"年度报告"
  Action: search_knowledge_base("年度报告 2025")
  Observation: 找到年度报告链接

  Thought: 可以先给用户报告链接
  Answer: 我没有找到直接的利润数据,但这里有一份 2025 年年度报告...

三、Tool Calling 实战

3.1 定义工具

javascript
const tools = [
  {
    name: 'search_knowledge_base',
    description: '搜索企业知识库',
    parameters: {
      type: 'object',
      properties: {
        query: { type: 'string' },
        limit: { type: 'number', default: 5 },
      },
      required: ['query'],
    },
    execute: async ({ query, limit }) => {
      const embedding = await getEmbedding(query);
      return await vectorDB.search(embedding, limit);
    },
  },
  {
    name: 'send_email',
    description: '发送邮件',
    parameters: {
      type: 'object',
      properties: {
        to: { type: 'string' },
        subject: { type: 'string' },
        body: { type: 'string' },
      },
      required: ['to', 'subject', 'body'],
    },
    execute: async ({ to, subject, body }) => {
      // 敏感操作,需要用户确认
      console.log(`准备发送邮件给 ${to},主题:${subject}`);
      return { status: 'sent' };
    },
  },
  {
    name: 'calculator',
    description: '执行数学计算',
    parameters: {
      type: 'object',
      properties: {
        expression: { type: 'string', description: '数学表达式,如 "2+3*4"' },
      },
      required: ['expression'],
    },
    execute: async ({ expression }) => {
      return eval(expression);  // 生产环境不要这样!仅 demo
    },
  },
];

3.2 Agent 循环

javascript
async function agentLoop(userQuery, maxSteps = 10) {
  const messages = [
    { role: 'system', content: `你是一个智能助手。可以使用工具来获取信息。
遇到不确定的事,先查工具再回答。不要编造信息。` },
    { role: 'user', content: userQuery },
  ];

  for (let step = 0; step < maxSteps; step++) {
    const response = await openai.chat.completions.create({
      model: 'gpt-4o',
      messages,
      tools: tools.map(t => ({
        type: 'function',
        function: { name: t.name, description: t.description, parameters: t.parameters },
      })),
    });

    const msg = response.choices[0].message;

    // 没有 tool call → LLM 决定回答了
    if (!msg.tool_calls) {
      return msg.content;
    }

    // 有 tool call → 执行工具
    for (const tc of msg.tool_calls) {
      const tool = tools.find(t => t.name === tc.function.name);
      const args = JSON.parse(tc.function.arguments);

      console.log(`[Step ${step}] 调用 ${tc.function.name}(${JSON.stringify(args)})`);

      try {
        const result = await tool.execute(args);
        messages.push({
          role: 'tool',
          tool_call_id: tc.id,
          content: JSON.stringify(result),
        });
      } catch (error) {
        messages.push({
          role: 'tool',
          tool_call_id: tc.id,
          content: JSON.stringify({ error: error.message }),
        });
      }
    }
  }

  return '抱歉,任务太复杂,我没能在限定步数内完成。';
}

// 使用
const answer = await agentLoop('帮我查一下公司去年的利润,算一下利润率');

四、Memory(记忆)

text
三层记忆:

1. 短期记忆 = 当前对话历史
   在 messages 数组里,受 Context Window 限制

2. 长期记忆 = 跨对话的信息
   存在 Vector DB 或数据库中
   下次对话前,检索相关历史

3. 工作记忆 = 当前任务的中间状态
   正在处理的文件、当前的搜索关键词
javascript
// 长期记忆示例
async function saveMemory(userId, content, metadata = {}) {
  const embedding = await getEmbedding(content);
  await db.memories.create({
    data: {
      userId,
      content,
      embedding: pgvector.toSql(embedding),
      metadata,
    },
  });
}

async function recallMemory(userId, query) {
  const embedding = await getEmbedding(query);
  const memories = await db.$queryRaw`
    SELECT content, metadata
    FROM memories
    WHERE user_id = ${userId}
    ORDER BY embedding <=> ${embedding}::vector
    LIMIT 5
  `;
  return memories;
}

五、Reflection(自我修正)

让 Agent 在行动后"反思"自己的表现:

text
三种 Reflection 模式:

1. 执行后反思
   Agent 完成一个任务 → 检查结果 → 不满意 → 重新做
   "我刚查到的资料里没有利润数据,换个关键词再查"

2. 关键决策点暂停
   涉及敏感操作 → 先解释理由 → 等待人工确认
   "我需要发送一封邮件给全体,确认后执行?"

3. 多轮辩论
   两个 Agent 角色互相质疑
   Agent A: "方案 1 更好,因为快"
   Agent B: "但方案 2 更安全,因为..."
   → 得出更周全的结论

六、LangGraph 入门

LangGraph 是 LangChain 的 Agent 框架,用**图(Graph)**定义 Agent 流程。

javascript
// 概念(不需要实际跑,理解结构即可)
import { StateGraph, END } from '@langchain/langgraph';

// 定义 Agent 的状态
const agentState = {
  messages: [],      // 对话历史
  next: 'agent',     // 下一步去哪
};

// 定义节点(每个节点是一个函数)
const agent = async (state) => {
  // LLM 决定:回答 or 调工具
  const response = await llm.invoke(state.messages);
  return { messages: [...state.messages, response], next: 'should_continue' };
};

const shouldContinue = (state) => {
  const lastMsg = state.messages[state.messages.length - 1];
  if (lastMsg.tool_calls) return 'tools';  // 有工具要调
  return END;                                // 结束了
};

const tools = async (state) => {
  // 执行工具
  const results = await executeTools(state.messages[state.messages.length - 1]);
  return { messages: [...state.messages, ...results], next: 'agent' };
};

// 构建图
const graph = new StateGraph({ channels: agentState })
  .addNode('agent', agent)
  .addNode('tools', tools)
  .addEdge('__start__', 'agent')      // 入口
  .addConditionalEdges('agent', shouldContinue, { tools: 'tools', [END]: END })
  .addEdge('tools', 'agent');         // 工具执行完回到 agent

const app = graph.compile();
text
Graph 可视化:

  __start__ → agent → (有 tool call?) → tools → agent → ... → END
                      ↘ (没有) → END

实践

  1. 写一个 3 个工具的 Agent:搜索知识库 + 计算器 + 获取当前时间
  2. 让 Agent 回答:"从 2020 年到今年经过了多少年?"(需要两步推理)
  3. 故意给 Agent 一个它解决不了的问题 → 观察它如何处理