Hello Agent | 第三章习题个人答案 #484
Unanswered
Mr-XcHan
asked this question in
💬 Exercises & Q&A
Replies: 2 comments
-
Q2. 在4.2节的 ReAct 实现中,我们使用了正则表达式来解析大语言模型的输出(如 Thought 和 Action)。请思考:Q2.1 当前的解析方法存在哪些潜在的脆弱性?在什么情况下可能会失败?当前的正则化匹配函数: 如果模型在 Thought 里提到字符串 "Action:",就可能被提前截断。 可以尝试 JSON 结构化输出, 结构清晰. |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
Q3. 计算器 R3. from dotenv import load_dotenv
load_dotenv()
import os
import ast
import operator as op
from serpapi import SerpApiClient
from typing import Dict, Any, Callable
# =========================
# 1. 搜索工具
# =========================
def search(query: str) -> str:
"""
一个基于SerpApi的实战网页搜索引擎工具。
它会智能地解析搜索结果,优先返回直接答案或知识图谱信息。
"""
print(f"🔍 正在执行 [SerpApi] 网页搜索: {query}")
try:
api_key = os.getenv("SERPAPI_API_KEY")
if not api_key:
return "错误:SERPAPI_API_KEY 未在 .env 文件中配置。"
params = {
"engine": "google",
"q": query,
"api_key": api_key,
"gl": "cn",
"hl": "zh-cn",
}
client = SerpApiClient(params)
results = client.get_dict()
if "answer_box_list" in results:
return "\n".join(map(str, results["answer_box_list"]))
if "answer_box" in results and "answer" in results["answer_box"]:
return str(results["answer_box"]["answer"])
if "knowledge_graph" in results and "description" in results["knowledge_graph"]:
return str(results["knowledge_graph"]["description"])
if "organic_results" in results and results["organic_results"]:
snippets = [
f"[{i+1}] {res.get('title', '')}\n{res.get('snippet', '')}"
for i, res in enumerate(results["organic_results"][:3])
]
return "\n\n".join(snippets)
return f"对不起,没有找到关于 '{query}' 的信息。"
except Exception as e:
return f"搜索时发生错误: {e}"
# =========================
# 2. 计算器工具
# =========================
_ALLOWED_OPERATORS = {
ast.Add: op.add,
ast.Sub: op.sub,
ast.Mult: op.mul,
ast.Div: op.truediv,
ast.FloorDiv: op.floordiv,
ast.Mod: op.mod,
ast.Pow: op.pow,
ast.USub: op.neg,
ast.UAdd: op.pos,
}
def _safe_eval(node):
if isinstance(node, ast.Expression):
return _safe_eval(node.body)
if isinstance(node, ast.Constant): # Python 3.8+
if isinstance(node.value, (int, float)):
return node.value
raise ValueError("仅支持整数和浮点数。")
if isinstance(node, ast.Num): # 兼容旧版本
return node.n
if isinstance(node, ast.BinOp):
left = _safe_eval(node.left)
right = _safe_eval(node.right)
operator_type = type(node.op)
if operator_type not in _ALLOWED_OPERATORS:
raise ValueError(f"不支持的运算符: {operator_type.__name__}")
return _ALLOWED_OPERATORS[operator_type](left, right)
if isinstance(node, ast.UnaryOp):
operand = _safe_eval(node.operand)
operator_type = type(node.op)
if operator_type not in _ALLOWED_OPERATORS:
raise ValueError(f"不支持的单目运算符: {operator_type.__name__}")
return _ALLOWED_OPERATORS[operator_type](operand)
raise ValueError("表达式中包含不被允许的语法。")
def calculator(expression: str) -> str:
"""
安全计算器工具,支持:
+, -, *, /, //, %, **, (), 正负号
"""
print(f"🧮 正在执行计算: {expression}")
try:
if not expression or not expression.strip():
return "错误:Calculator 的输入不能为空。"
# 兼容中文数学符号
normalized = (
expression.replace("×", "*")
.replace("÷", "/")
.replace("(", "(")
.replace(")", ")")
.replace(",", ",")
.replace("=", "=")
.replace(" ", "")
)
# 去掉结尾的 = 号
if normalized.endswith("="):
normalized = normalized[:-1]
tree = ast.parse(normalized, mode="eval")
result = _safe_eval(tree)
# 让整数结果更美观
if isinstance(result, float) and result.is_integer():
result = int(result)
return f"计算结果:{result}"
except ZeroDivisionError:
return "错误:除数不能为 0。"
except Exception as e:
return f"错误:无法计算表达式 '{expression}',原因: {e}"
# =========================
# 3. ToolExecutor
# =========================
class ToolExecutor:
"""
一个工具执行器,负责管理和执行工具。
"""
def __init__(self):
self.tools: Dict[str, Dict[str, Any]] = {}
def registerTool(self, name: str, description: str, func: Callable[[str], str]):
if name in self.tools:
print(f"警告:工具 '{name}' 已存在,将被覆盖。")
self.tools[name] = {
"description": description,
"func": func
}
print(f"工具 '{name}' 已注册。")
def getTool(self, name: str) -> Callable[[str], str]:
return self.tools.get(name, {}).get("func")
def getAvailableTools(self) -> str:
return "\n".join([
f"- {name}: {info['description']}"
for name, info in self.tools.items()
])
def executeTool(self, name: str, tool_input: str) -> Dict[str, Any]:
"""
更可靠的工具执行接口:
返回结构化结果,而不是只返回字符串。
"""
if name not in self.tools:
return {
"success": False,
"tool_name": name,
"input": tool_input,
"output": None,
"error": f"未找到名为 '{name}' 的工具。",
"hint": f"请从以下工具中选择:{', '.join(self.tools.keys())}"
}
try:
func = self.tools[name]["func"]
output = func(tool_input)
# 约定:如果字符串以“错误:”开头,则视为失败
if isinstance(output, str) and output.startswith("错误:"):
return {
"success": False,
"tool_name": name,
"input": tool_input,
"output": None,
"error": output,
"hint": self._build_hint(name)
}
return {
"success": True,
"tool_name": name,
"input": tool_input,
"output": output,
"error": None,
"hint": None
}
except Exception as e:
return {
"success": False,
"tool_name": name,
"input": tool_input,
"output": None,
"error": f"工具执行异常: {e}",
"hint": self._build_hint(name)
}
def _build_hint(self, tool_name: str) -> str:
if tool_name == "Calculator":
return "Calculator 只适合数学表达式,例如: (123+456)*789/12"
if tool_name == "Search":
return "Search 适合查询事实、新闻、产品信息等,例如: 华为最新手机是哪款"
return "请检查工具名称和输入参数格式是否正确。"
# =========================
# 4. 使用示例
# =========================
if __name__ == '__main__':
toolExecutor = ToolExecutor()
search_description = "一个网页搜索引擎。当你需要回答关于时事、事实以及在你的知识库中找不到的信息时,应使用此工具。"
calculator_description = "一个计算器工具。适用于数学表达式计算,例如 (123+456)*789/12"
toolExecutor.registerTool("Search", search_description, search)
toolExecutor.registerTool("Calculator", calculator_description, calculator)
print("\n--- 可用的工具 ---")
print(toolExecutor.getAvailableTools())
print("\n--- 执行 Calculator ---")
result = toolExecutor.executeTool("Calculator", "(123 + 456) × 789 / 12 =")
print(result)
''' |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Q1. 本章介绍了三种经典的智能体范式:ReAct、Plan-and-Solve 和 Reflection。请分析:
Q1.1 这三种范式在"思考"与"行动"的组织方式上有什么本质区别?
R1.1:
ReAct: “思考”和“行动”是交替进行, 不一定先有完整计划,而是在执行过程中不断修正.
Plan-and-Solve: 先规划、后执行, 重视任务分解, 执行过程更有条理.
Reflection:行动之后再反思和优化.
Q1.2 如果要设计一个"智能家居控制助手", 选择哪种范式?
R1.2 我会选择ReAct方式。首先ReAct范式可以根据环境的反馈进行调整,具体的环境可以通过fuction tool来获取。这样的任务实际可能无需plan,也无需reflection.
Q1.3 是否可以将这三种范式进行组合使用?
R1.3 必须可以! 而且感觉这三者恰恰非常适合组合使用:
1.Plan-and-Solve 负责全局规划
2.ReAct 负责执行中的动态响应
3.Reflection 负责事后总结和长期优化
Beta Was this translation helpful? Give feedback.
All reactions