17-day4-鲁棒性-外挂工具协作_练习1

为 LangChain Agent 添加更多实用的小工具(tools)

工具
unit_converter 覆盖日常高频需求,输入自然,无需复杂配置
text_utils 轻量、无依赖、实用性强,适合演示和真实场景

🔒 零外部依赖:两个包都只使用 Python 标准库(re, random, string 等),无需额外 pip install


📦 工具包 1:unit_converter —— 单位换算器

功能

支持常见单位之间的转换(长度、重量、温度、面积等),输入自然语言描述即可。

文件结构

unit_converter/
├── __init__.py
└── converter.py

unit_converter/converter.py

# unit_converter/converter.py
import re
from typing import Optional

# 定义换算因子(以国际单位为基准)
CONVERSIONS = {
    # 长度 (米)
    "km": 1000, "m": 1, "cm": 0.01, "mm": 0.001,
    "inch": 0.0254, "ft": 0.3048, "yd": 0.9144, "mi": 1609.344,
    # 重量 (千克)
    "kg": 1, "g": 0.001, "mg": 1e-6,
    "lb": 0.453592, "oz": 0.0283495,
    # 温度(特殊处理)
    "celsius": "temp", "fahrenheit": "temp", "kelvin": "temp",
    # 面积 (平方米)
    "m2": 1, "cm2": 1e-4, "km2": 1e6,
    "acre": 4046.86, "hectare": 10000,
}

def _parse_input(query: str) -> tuple[Optional[float], str, str]:
    """解析 '5 km to miles' 类型的输入"""
    query = query.strip().lower()
    # 支持格式: "5 km to mi", "convert 100 f to c"
    pattern = r"^(?:convert\s+)?([\d\.]+)\s+(\w+)\s+(?:to|in)\s+(\w+)$"
    match = re.match(pattern, query)
    if not match:
        return None, "", ""
    value = float(match.group(1))
    from_unit = match.group(2).replace("²", "2").replace(" ", "")
    to_unit = match.group(3).replace("²", "2").replace(" ", "")
    return value, from_unit, to_unit

def convert_unit(query: str) -> str:
    """
    将一个单位转换为另一个单位。
    示例输入:
      "5 km to miles"
      "100 fahrenheit to celsius"
      "2 acres to m2"
    """
    try:
        value, from_u, to_u = _parse_input(query)
        if value is None:
            return "❌ 格式错误。请使用: '<数值> <原单位> to <目标单位>',例如 '5 km to mi'"

        if from_u not in CONVERSIONS or to_u not in CONVERSIONS:
            return f"❌ 不支持的单位: {from_u} 或 {to_u}"

        # 温度特殊处理
        if CONVERSIONS[from_u] == "temp" and CONVERSIONS[to_u] == "temp":
            if from_u == to_u:
                return f"{value}°{from_u.upper()} = {value}°{to_u.upper()}"
            # 转为摄氏
            if from_u == "fahrenheit":
                c = (value - 32) * 5/9
            elif from_u == "kelvin":
                c = value - 273.15
            else:
                c = value
            # 从摄氏转出
            if to_u == "fahrenheit":
                res = c * 9/5 + 32
            elif to_u == "kelvin":
                res = c + 273.15
            else:
                res = c
            return f"{value}°{from_u.title()} = {res:.2f}°{to_u.title()}"

        # 其他单位:通过国际单位中转
        base_value = value * CONVERSIONS[from_u]
        result = base_value / CONVERSIONS[to_u]
        return f"{value} {from_u} = {result:.4g} {to_u}"

    except Exception as e:
        return f"❌ 转换失败: {str(e)}"

robust_agent_3.py 中集成

from unit_converter.converter import convert_unit

@tool
def unit_converter(query: str) -> str:
    """单位换算工具。示例:'5 km to miles', '100 fahrenheit to celsius'"""
    return convert_unit(query)

# 加入 tools 列表
tools = [ ..., unit_converter]

📦 工具包 2:text_utils —— 文本处理小工具箱

功能

提供字数统计、文本摘要(简单截断)、大小写转换、生成密码等。

文件结构

text_utils/
├── __init__.py
└── utils.py

text_utils/utils.py

# text_utils/utils.py
import random
import string

def word_count(text: str) -> str:
    words = text.split()
    chars = len(text)
    return f"字数: {len(words)} | 字符数(含空格): {chars}"

def summarize_text(text: str, max_length: int = 100) -> str:
    if len(text) <= max_length:
        return text
    return text[:max_length].rsplit(' ', 1)[0] + "…"

def to_uppercase(text: str) -> str:
    return text.upper()

def to_lowercase(text: str) -> str:
    return text.lower()

def generate_password(length: int = 12) -> str:
    if length < 4 or length > 100:
        return "密码长度应在 4~100 之间"
    chars = string.ascii_letters + string.digits + "!@#$%"
    return ''.join(random.choice(chars) for _ in range(length))

def text_tool(action: str) -> str:
    """
    多功能文本工具。支持:
    - "count: 你的文本" → 统计字数
    - "summarize: 很长的文本..." → 生成摘要
    - "upper: hello" → HELLO
    - "lower: HELLO" → hello
    - "password: 12" → 生成12位密码
    """
    action = action.strip()
    if action.startswith("count:"):
        return word_count(action[6:].strip())
    elif action.startswith("summarize:"):
        return summarize_text(action[10:].strip())
    elif action.startswith("upper:"):
        return to_uppercase(action[6:].strip())
    elif action.startswith("lower:"):
        return to_lowercase(action[6:].strip())
    elif action.startswith("password:"):
        try:
            length = int(action[9:].strip())
            return generate_password(length)
        except:
            return generate_password(12)
    else:
        return "支持命令: count:, summarize:, upper:, lower:, password:"

robust_agent_3.py 中集成

from text_utils.utils import text_tool

@tool
def text_tool_agent(command: str) -> str:
    """
    文本处理工具。用法:
    - "count: 今天天气真好"
    - "summarize: 这是一段非常非常长的文本..."
    - "upper: hello world"
    - "password: 16"
    """
    return text_tool(command)

# 加入 tools 列表
tools = [ ..., text_tool_agent]


📂 最终项目结构建议

your_project/
├── robust_agent_3.py
├── money_divination/
├── unit_converter/
│   ├── __init__.py
│   └── converter.py
└── text_utils/
    ├── __init__.py
    └── utils.py

然后在 robust_agent_3.py 开头导入:

from money_divination.core.divination_tool import perform_divination
from unit_converter.converter import convert_unit
from text_utils.utils import text_tool

💬 用户可提问示例

  • “把 98 华氏度转成摄氏度”
  • “5 英里等于多少公里?”
  • “统计这段文字的字数:人工智能是未来”
  • “生成一个 16 位的强密码”

Agent 会自动选择合适的工具执行!


需要我帮你生成完整的 .zip 或打包脚本,或者再加一个“天气查询(模拟)”、“汇率换算(模拟)”工具吗?欢迎继续提出!

posted @ 2026-01-28 22:09  船山薪火  阅读(19)  评论(0)    收藏  举报
![image](https://img2024.cnblogs.com/blog/3174785/202601/3174785-20260125205854513-941832118.jpg)