AI Agent = LLM(大语言模型)+ 控制逻辑(Control Logic)+ 工具/环境接口
TAO
Thought-Action-Observation (TAO) 是 AI Agent 的完整的工作流程。在许多 Agent 框架中,规则和指示是被直接嵌入到 System prompt 中的,确保每个循环都遵循定义的逻辑。就是说,在后端,输入给 LLM 的 prompt 总是会有一些预设的信息,比如,有哪些 Tools 可以使用,等。
三步循环中可以看出:
- 代理会不断循环上述三步骤,直到目标较好地达成。
- 第三步 Observation 其实是将上一部 Action 的结果拿到。在下一次循环中使用。
- 动态适应:每个循环都允许代理将最新的信息(Observation 结果)纳入其推理(Thought)中,从而确保最终的答案是信息充分且准确的。
上述循环称作 ReAct(Resoning & Acting) cycle。
ReAct 或 TAO 是在 Prompting 层实现的,通过精心设计的 prompt 和外部执行循环,引导 LLM 模仿TAO 这种范式。这不是 LLM 的能力(LLM只负责generate)。LLM 不知道自己在做 ReAct。ReAct 有Agent 框架负责控制。
外部执行循环
是Agent系统中的开发者编写的控制逻辑,它反复调用 LLM,解析其输出,执行响应的工具,累积上下文,直到任务完成。
LLM 是stateless 的,每次调用都是独立的,(除非你把历史写入 prompt,就可以理解上下文了)并且不负责调用各种tools。
KAQ: 如何将历史写入 prompt
在外部执行循环中,使用 += 将外部信息(包括历史)写入 prompt。如:
prompt = build_initial_prompt(user_question, tools_description)
while not final_answer and step < max_steps:
# 1. 调用 LLM(只生成一次响应)
llm_output = llm.generate(prompt)
# 2. 解析 LLM 输出:提取 Thought / Action / Final Answer
parsed = parse_react_output(llm_output)
if "final_answer" in parsed:
final_answer = parsed["final_answer"]
break
elif "action" in parsed:
# 3. 执行工具(在 LLM 外部)
tool_name = parsed["action"]["name"]
args = parsed["action"]["args"]
observation = execute_tool(tool_name, args) # <- 真正调用计算器、搜索等
# 4. 将观察结果拼回 prompt,形成新上下文 <- 这里将关键信息写入prompt
prompt += f"\nThought: {parsed['thought']}"
prompt += f"\nAction: {tool_name}({args})"
prompt += f"\nObservation: {observation}"
else:
raise Error("LLM output format invalid")
Thought
ReAct 是一种简单的 Prompting 技术,在让 LLM 解码下一个标记之前,他会添加(prompt += …) “让我们一步一步地思考”。“一步一步地思考”会鼓励模型解码过程朝着生成计划而不是最终解决方案的方向发展,因为模型被鼓励将问题分解为子任务。分解成子步骤,就是 Deepseek R1 或 OpenAI 的 o1 这类模型背后的原理,它们被微调成 “在回答之前思考”。
这些训练好的模型包含特定的思考部分(在<think>和</think> special token 之间)。这不仅仅是一种像 ReAct 这样的 Prompting 技术,而是一种训练方法。
这一步是由 LLM 完成的。
KAQ:TAO-cycle 和 ReAct 的区别
TAO 是一个更通用的概念,描述了 AI Agent 与环境交互的基本循环过程 。它强调了 Agent 需要思考、行动、并观察行动的结果,然后根据观察到的结果进行下一步的思考和行动。这是一个基础模型。
ReAct 是一个更具体的框架,它在 TAO 循环的基础上,特别强调了推理 (Reasoning) 的重要性 。ReAct Agent 不仅仅是简单地思考和行动,而是会生成详细的推理轨迹,用于指导行动,并处理异常情况。这是个具体实现。
Ation
Agent 类型:
- JSON agent
- Code agent
- Function-call agent
Action 的类型:
- 信息收集
- Tools使用
- 环境交互
- Communication
LLM 只能处理文本,使用文本来描述 Agent 想要执行的动作,和传给工具的参数。LLM 必须 STOP 继续生成 Tokens,接着将控制权从 LLM 交给 Agent,以确保 Action 的结果是可解析的。
KAQ: 为什么要 STOP 继续生成 Tokens
LLM 只做一件事: 文本生成。故它会不断地生成 token (文本片段),直到满足停止条件。如果 LLM 不停止生成 token,它可能会在行动指令之后继续生成一些无意义的文本,导致 Agent 无法正确解析指令。
KAQ:确保 Action 的结果是可解析的,什么意思?
可解析(parsability)的作用是可通过控制逻辑将解析到的结果 append 到 prompt。以便 LLM 下一轮推理使用。
需要是这样的:Action: calculator(a=12, b=34),而不是这样的:I think I should multiply 12 and 34 using the calculator.
看,只有前者才能被外部执行循环 code 解析。
STOP 和 parse LLM 结果的方法
第一步:Agent 输出预定的格式的 Actions。
第二步:Stop token 的生成。
第三步:外部解析器解析格式化的 action,确定要调用的 tools 并给出参数。
CodeAgent
Code Agent 是这样:
![]() |
|---|
| Code agent |
图片来自:Executable Code Actions Elicit Better LLM Agents
不是输出一个简单的 JSON 对象,Code Agent 利用其内部的 LLM 生成一段可执行的代码(通常是 Python),然后由外部控制逻辑执行该代码并获取结果。用户也可以预先提供自定义工具(函数),供 LLM 在生成时调用。
这种输出的优点:
- 表达能力强
- 模块化和可复用
- 调试能力强
- Code Agent 可直接集成外部库和API
实例:
# Code Agent Example: Retrieve Weather Information
def get_weather(city):
import requests
api_url = f"https://api.weather.com/v1/location/{city}?apiKey=YOUR_API_KEY"
response = requests.get(api_url)
if response.status_code == 200:
data = response.json()
return data.get("weather", "No weather information available")
else:
return "Error: Unable to fetch weather data."
# Execute the function and prepare the final answer
result = get_weather("New York")
final_answer = f"The current weather in New York is: {result}"
print(final_answer)
通过明确界定代码块并指示执行完成(在这里,通过打印 final_answer)表示 STOP 在这里。
JSON agent 例子可以是这样:
Thought: I need to check the current weather for New York.
Action :
{
"action": "get_weather",
"action_input": {"location": "New York"}
}
KAQ:CodeAgent 是根据什么生成一段可执行的代码块
构造包含用户问题和系统指令的 prompt;然后 调用LLM 生成代码文本;在沙盒中解析并执行code;将结果 += 到Prompt;后续步骤…
KAQ:JSON 或 Code 是谁生成的
LLM 生成的
- LLM 根据用户的输入和设定的 Prompt,生成包含 action 和 action_input 字段的 JSON,用于指定要执行的操作和参数。控制逻辑执行特定的任务
- LLM 根据用户的输入和设定的 Prompt,生成包含 code 的字符串,用于控制逻辑执行特定的任务。
Observe
Observation 提供给 Agent 关键信息,为 Agent 的思考过程提供动力,并指导未来的行为。Observation 是来自环境的反馈,可以是来自 API 的数据、错误消息,还可以来自系统日志,这些信号被用于指导下一轮的 Thought。
Observation 获取工具执行的结果,并将其结构化地反馈给 LLM,作为下一步推理的上下文。
在 Observation 阶段,Agent 做的事:
- 收集反馈:接收其行动是否成功的或确认的数据
- 添加结果:将新信息整合到其现有上下文中,有效地更新其记忆。
- 调整其策略:使用更新后的上下文来优化随后的思考和行动。
KAQ: 如果一个任务需要 3 个 TAO 循环,LLM 确实会被调用 3 次,每次调用的输入都会包含之前循环中产生的新的信息和反馈。对吗?
是的,控制逻辑中通过 “+=”
每次 LLM 被调用时,它接收到的输入通常包括:
- 系统提示 (System Prompt):定义 Agent 的行为、可用的工具和 TAO 循环的规则 3。
- 用户输入 (User Input):用户提出的问题或指令。
- 历史信息 (History):之前循环中的 Thought、Action 和 Observation 记录。
通过这种方式,Agent 可以在每个循环中不断学习和调整,最终完成任务。
KAQ:接上,3 个 TAO 循环过程中系统 prompt 内容是在不断增加的?
System prompt 本身通常不变。它是chat系统开始时的基本设定。它不变。但是整个输入prompt 因包含了上一次 TAO 内容而不断增长。
Observation 有多种形式:各种可用的外部信息
错误消息、成功通知、状态码;数据库更新、文件系统修改、状态变更;传感器读数,系统指标,资源使用情况,比如机械臂位置;API 响应,查询结果,计算输出;到达截止日期,计划任务完成。
KAQ:prompt 类型和 messages
- system prompt: 设定规则
- user prompt: 提出问题
- assistant prompt: 保留历史,将之前的回复也作为本轮的输入一部分
这三者构成了 input prompt。
这些角色 prompt 会被 tokenizer 的 chat template 按照模型训练时的格式(如 <|user|>...<|assistant|>...)拼接成最终的 输入 prompt(input prompt),送入 LLM。
完成的 对话构成了 messages:
messages = [
{"role": "system", "content": "You are a tech support agent."},
{"role": "user", "content": "I can't log in."},
{"role": "assistant", "content": "Have you tried resetting your password?"},
{"role": "user", "content": "Yes, but I didn't receive the email."}
]
Few-shot
他表示 1~3 个高质量示例,通常放在 Systems prompt 中:
You are an agent that uses tools. Use the following format:
Thought: [reasoning]
Action: calculator(a=..., b=...)
Observation: [result]
... (repeat if needed)
Final Answer: ...
Example 1:
Question: What is 5 * 6?
Thought: I need to multiply 5 and 6.
Action: calculator(a=5, b=6)
Observation: 30
Thought: Now I know the result.
Final Answer: 30
Now solve this:
Question: What is 12 * 13?
这是让 LLM 稳定输出 Thought/Action/Observation 等结构化内容的最有效提示技巧之一
