PatchPal:极简AI编码代理实现

代理编码助手现在已广泛普及(例如Aider、Claude Code、OpenCode)。在花时间使用Claude Code和OpenCode后,我想要一些可以在本地运行、端到端检查、无需浏览大型框架即可修改和扩展的东西。

这种好奇心导致了开发一个开源的、基于Python的代理编码助手,名为PatchPal

**PatchPal**是一个精简的受Claude Code启发的AI编码代理,纯粹用Python实现,旨在帮助完成以下工作:

  • 构建、调试和修改软件
  • 数据分析和可视化,包括通过网页抓取和API交互进行数据策划
  • 研究问题并报告综合发现(例如网页搜索、日志文件分析)
  • 自动化任务并使用技能、工具和即时代码生成/执行解决问题
    基于权限的交互模型与Claude Code使用的模型一致,提供了熟悉的工作流程。

与许多较大的编码代理不同,PatchPal故意保持小巧和透明

$ ls patchpal
__init__.py  agent.py  cli.py  context.py  permissions.py
skills.py    system_prompt.md  tool_schema.py tools.py

1、如何安装

PatchPal通过PyPI分发:

pip install patchpal

支持Linux、macOS和Windows

2、快速开始

PatchPal支持通过LiteLLM使用云模型本地模型

选项1:云模型(最快尝试)

设置API密钥并运行patchpal命令:

# 使用Anthropic(默认模型目前是Claude Sonnet 4.5)
export ANTHROPIC_API_KEY=your_key_here
patchpal

# 使用Anthropic的Claude Opus 4.5代替默认模型
patchpal --model anthropic/claude-opus-4-5

# 使用OpenAI模型
export OPENAI_API_KEY=your_key_here
patchpal --model openai/gpt-5.2 # 或gpt-5-mini、gpt-4o等

# 使用LiteLLM包支持的任何提供商
# 例如,AWS上的bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0
patchpal --model <在此输入litellm模型路径>

PatchPal兼容LiteLLM包支持的每个LLM提供商。默认模型目前是Anthropic的Claude Sonnet 4.5——与Claude Code相同。

选项2:使用Ollama的本地模型

Ollama也很好用,有一个重要要求:你必须将上下文窗口增加到至少32K token。

# 必需:增加上下文大小
export OLLAMA_CONTEXT_LENGTH=32768

# 启动Ollama
ollama serve

# 使用Ollama运行PatchPal
patchpal --model ollama_chat/gpt-oss:20b

没有更大的上下文窗口,代理工作流会以微妙的方式失败——这是最常见的Ollama陷阱。此外,并非所有Ollama模型都能在工具调用代理工作流中很好地工作。Ollama推荐的一些模型是gpt-ossqwen3-coder

选项3:使用vLLM的本地模型

如果你有较大的GPU,你还可以使用vLLM以更高性能的方式本地运行模型。

vllm serve openai/gpt-oss-20b \
  --api-key token-abc123 \
  --tool-call-parser openai \
  --enable-auto-tool-choice

然后,在另一个终端:

export HOSTED_VLLM_API_BASE=http://localhost:8000
export HOSTED_VLLM_API_KEY=token-abc123
patchpal --model hosted_vllm/openai/gpt-oss-20b

示例任务

启动后,PatchPal支持与Claude Code类似的对话交互。

3、构建应用或新功能

在下面的示例中,我们使用从SCOTUSblog网页抓取的数据构建一个最高法院案件的Streamlit仪表板。最终应用包括仪表板和一个用于收集和策划数据的网页抓取脚本。

图片

应用构建示例。### 3.1 修复错误

IEEE Spectrum最近发表了一篇题为AI编码助手正在变得更糟的文章。然而,我们发现文章中的实验不支持作者的中心主张。下面的示例演示了作者声称当前LLM无法可靠解决的以下代码问题的解决方案:

# 损坏的代码
df = pd.read_csv('data.csv')
df['new_column'] = df['index_value'] + 1 #没有'index_value'列

图片

错误修复示例### 3.2 数据分析和可视化

除了代码编辑之外,代理编码助手还可用于数据分析和可视化,以及数据策划和网页抓取。

在生成前5个下载量最大的Python包的条形图时,代理将默认遵循透明的、基于权限的工作流程:

  • 来源识别:代理启动自主网页搜索以识别Python包下载统计数据的权威数据源。它首先请求用户许可继续执行建议的搜索查询。
  • 数据获取:在找到合适的数据源后,代理提示用户许可访问(下载和解析)分析所需的网页内容。
  • 代码生成和执行:然后代理生成必要的Python代码来处理数据、创建条形图并显示可视化。它在执行此代码之前请求最终用户授权。
    图片

数据分析和可视化示例## 4、技能:可复用的代理工作流

PatchPal还支持 代理技能,这是一种用于用Markdown编写的可复用、命名工作流的开放格式。

你可以使用skills-creator技能为代理创建新技能,然后简单地将它们放到~/.patchpal/skills文件夹中供PatchPal使用。(Anthropic还维护着一个更大的代理技能公共存储库,所有这些都与PatchPal兼容。)

图片

PatchPal的可配置技能系统## 5、创建你自己的工具

虽然技能为代理提供了要遵循的指令和模板,但自定义工具通过可执行的Python函数扩展了代理的功能,这些函数按需运行。

将一个.py文件放到~/.patchpal/tools/中,PatchPal会在启动时自动发现并集成你的函数。然后代理可以像调用任何内置工具一样调用它们。

实现很简单:编写一个带有类型提示和文档字符串的函数,PatchPal会自动生成LLM工具模式。希望代理查询你的数据库?解析你的自定义文件格式?调用你公司的API?只需编写函数,代理就知道如何使用它。

在下面的示例中,我们实现了一个简单的计算器工具calculator.py,代理可以使用它。

"""文件名:calculator.py

PatchPal的示例自定义工具。

此文件演示如何创建扩展PatchPal功能的自定义工具。工具从~/.patchpal/tools/自动发现

工具函数的要求:
- 所有参数的类型提示
- 带有描述和Args部分的文档字符串
- 模块级函数(非嵌套)
- 返回类型通常应为str(供LLM消费)
"""

def add(x: int, y: int) -> str:
    """将两个数字相加。

    Args:
        x: 第一个数字
        y: 第二个数字

    Returns:
        和作为字符串
    """
    result = x + y
    return f"{x} + {y} = {result}"

def subtract(x: int, y: int) -> str:
    """减去两个数字。

    Args:
        x: 第一个数字
        y: 从x中减去的第二个数字

    Returns:
        差作为字符串
    """
    result = x - y
    return f"{x} - {y} = {result}"

def multiply(x: float, y: float) -> str:
    """将两个数字相乘。

    Args:
        x: 第一个数字
        y: 第二个数字

    Returns:
        积作为字符串
    """
    result = x * y
    return f"{x} × {y} = {result}"

def divide(x: float, y: float) -> str:
    """将两个数字相除。

    Args:
        x: 分子
        y: 分母

    Returns:
        商作为字符串
    """
    if y == 0:
        return "错误:不能除以零"
    result = x / y
    return f"{x} ÷ {y} = {result}"

工具在需要时由代理自动使用:

你:12345*654是多少?

🤔 思考中...
🔧 multiply({'x': 12345, 'y': 654})
🤔 思考中...

===================================
代理
===================================
12345 × 654 = 8,073,630
===================================

自定义工具超越了文件操作和shell命令,进入特定领域的任务——分析业务数据、检查系统健康、处理自定义文件格式或与内部API集成。代理可以直接访问你审查过的函数,而无需通过shell命令即时生成和执行代码。

自定义工具在终端CLI(自动发现)和Python API(作为参数传递)中都可用,这将在接下来讨论。

6、通过Python访问PatchPal

PatchPal也可以从Python脚本或REPL中以编程方式使用,通过简单的API提供完整的代理功能。

在Python API中,自定义工具可以直接提供给create_agent。在下面的示例中,我们为代理提供了一个用于搜索GitHub仓库的自定义工具。

from patchpal.agent import create_agent

# 用于搜索GitHub仓库的自定义工具
from typing import Optional
import requests
def search_github_repos(query: str, language: Optional[str] = None, max_results: int = 5) -> str:
    """按关键词搜索GitHub仓库。

    Args:
        query: 搜索查询(例如"machine learning"、"web framework")
        language: 可选的编程语言过滤器(例如"Python"、"JavaScript")
        max_results: 返回的最大结果数(默认:5)

    Returns:
        格式化的仓库列表,包含星标数、描述和URL
    """
    if requests is None:
        return "错误:未安装'requests'库。使用以下命令安装:pip install requests"

    try:
        search_query = query
        if language:
            search_query += f" language:{language}"

        url = "https://api.github.com/search/repositories"
        params = {"q": search_query, "sort": "stars", "order": "desc", "per_page": max_results}

        response = requests.get(url, params=params, timeout=10)

        if response.status_code != 200:
            return f"错误:GitHub API请求失败(HTTP {response.status_code})"

        data = response.json()
        repos = data.get("items", [])

        if not repos:
            return f"未找到'{query}'的仓库"

        result = [f"找到{len(repos)}个'{query}'的仓库"]
        if language:
            result[0] += f"(语言:{language})"
        result.append("")

        for i, repo in enumerate(repos, 1):
            stars = repo["stargazers_count"]
            forks = repo["forks_count"]
            language_name = repo["language"] or "N/A"

            result.append(f"{i}. {repo['full_name']} ⭐ {stars:,} 🍴 {forks:,}")
            result.append(f"   语言:{language_name}")

            description = repo["description"] or "无描述"
            if len(description) > 100:
                description = description[:97] + "..."
            result.append(f"   {description}")
            result.append(f"   {repo['html_url']}")
            result.append("")

        return "\n".join(result)

    except requests.exceptions.Timeout:
        return "错误:搜索GitHub时请求超时"
    except requests.exceptions.ConnectionError:
        return "错误:无法连接到GitHub API。请检查你的互联网连接。"
    except KeyError as e:
        return f"错误:来自GitHub API的意外响应格式:缺少{e}"
    except Exception as e:
        return f"搜索GitHub时出错:{str(e)}"

# 使用自定义工具创建代理
agent = create_agent(
    model_id="anthropic/claude-sonnet-4-5",
    custom_tools=[search_github_repos]
)

# 使用代理 - 它会在适当的时候调用你的自定义工具
response = agent.run("给我看一些ML GitHub仓库")
print(response)

# 所有内置工具仍然可用(例如web_search、run_shell等)
response = agent.run("搜索法院案件的数据源")
print(response)

7、配置、安全和护栏

PatchPal包括安全控制、上下文管理和执行限制,允许你使代理适应不同的环境和风险承受能力。

默认情况下,采用受Claude Code启发的安全模型,包括:

  • shell命令和文件修改的权限提示* 阻止特权升级和危险命令(例如sudorm -rf)* 审计日志记录和可选的自动文件备份* 用于安全探索和分析的只读模式
    这降低了在典型、现实场景中发生意外更改的风险。

范围和适用性

如果你有以下情况,PatchPal很适合:

  • 喜欢Claude Code的交互模型
  • 想要可以使用本地模型运行的东西
  • 偏好可以轻松扩展和配置的基于Python的工具* 希望占用空间小
    这项工作的一个关键目标是涵盖与大型代理框架相同的基础——模型支持、工具使用、代码库导航、代理技能和多步骤任务——同时优先考虑简单性、可配置性和端到端清晰度。

最后,借助对代理技能自定义工具的支持,并由显式的权限系统保护,代理可用于代码编辑之外的一般问题解决任务。


原文链接:PatchPal:极简AI编码代理实现 - 汇智网

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐