Download the PHP package likun-mci/php-ai without Composer

On this page you can find all versions of the php package likun-mci/php-ai. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package php-ai

PHP AI 标准库

一个框架无关的 PHP AI 调用标准库,用统一接口屏蔽 40 个国内外主流 AI 平台鉴权方式、请求协议、返回格式、流式协议上的差异——国内的通义千问、豆包、文心一言、智谱 GLM、Kimi、腾讯混元、讯飞星火、DeepSeek……,海外的 OpenAI、Claude、Gemini、Grok、Mistral……,以及 OpenRouter、硅基流动等聚合中转与 Ollama 等本地部署。切换平台只需换一个配置项。

除对话能力外,还内置了 Agent 工具调用循环AI 代码编辑协议带 SSRF 防护的网页抓取工具Agent 长期记忆,可直接用于构建后台 AI 助手、代码编辑助手、内容翻译等实际业务。

本文档中的示例均来自真实业务系统(一套 CodeIgniter 3 的建站系统)中的实际用法,非伪代码。

🌏 English documentation: README-en.md


特性


环境要求

项目 要求
PHP >= 7.1
扩展 ext-curlext-jsonext-mbstringext-dom(仅 HTML 转换用到)
网络 可访问对应平台 API;中国环境通常需配置代理,见 网络代理

安装

Composer

手动引入(不使用 Composer)

库自带 PSR-4 加载器,把整个目录放进项目后引入一次即可:


快速开始

换成国产平台,只需改配置——业务代码一行不用动:

完整的平台清单见 支持的平台与模型,可运行的示例见 examples_platforms.php

chat() 接受字符串(自动包装为一条 user 消息)或完整 payload 数组:

多轮对话:默认不保存历史(messages 由业务层完整传入)。若想让库自动维护上下文,设 rounds 即可,见 多轮对话上下文。


支持的平台与模型

平台一览

protocol 传下表中的取值,api_key 传该平台控制台的密钥,其余写法所有平台完全一致:

中国大陆主流平台

平台 protocol 取值 默认端点 模型名自动识别
DeepSeek 深度求索 deepseek
别名 deepseek-ai
api.deepseek.com/v1/chat/completions deepseek-*
阿里云百炼(通义千问) qwen
别名 dashscope / bailian / tongyi / aliyun
dashscope.aliyuncs.com/compatible-mode/v1/chat/completions qwen*qwq*
阿里云百炼(通义千问) qwen-anthropic
别名 qwen-claude / dashscope-anthropic
dashscope.aliyuncs.com/api/v2/apps/claude-code-proxy/v1/messages
火山方舟(豆包) doubao
别名 ark / volcengine / volces / volc
ark.cn-beijing.volces.com/api/v3/chat/completions doubao-*
百度千帆(文心一言) ernie
别名 qianfan / baidu / wenxin / yiyan
qianfan.baidubce.com/v2/chat/completions ernie-*
智谱 AI(GLM) zhipu
别名 glm / bigmodel / chatglm / zhipuai
open.bigmodel.cn/api/paas/v4/chat/completions glm-*cogview-*
智谱 AI(GLM) zhipu-anthropic
别名 glm-anthropic / zhipu-claude
open.bigmodel.cn/api/anthropic/v1/messages
月之暗面(Kimi) moonshot
别名 kimi / yuezhianmian
api.moonshot.cn/v1/chat/completions kimi-*moonshot-*
月之暗面(Kimi) moonshot-anthropic
别名 kimi-anthropic / moonshot-claude
api.moonshot.cn/anthropic/v1/messages
腾讯混元 hunyuan
别名 tencent / tencent-hunyuan
api.hunyuan.cloud.tencent.com/v1/chat/completions hunyuan-*
讯飞星火 spark
别名 xunfei / iflytek / xfyun / xinghuo
spark-api-open.xf-yun.com/v1/chat/completions spark*4.0Ultra
MiniMax(稀宇科技) minimax
别名 xiyu / minimaxi
api.minimaxi.com/v1/text/chatcompletion_v2 MiniMax-*abab*
阶跃星辰(Step) stepfun
别名 step / jieyue
api.stepfun.com/v1/chat/completions step-*
零一万物(Yi) yi
别名 lingyiwanwu / 01ai / 01-ai / zeroone
api.lingyiwanwu.com/v1/chat/completions yi-*
百川智能 baichuan
别名 baichuan-inc
api.baichuan-ai.com/v1/chat/completions Baichuan*
商汤日日新(SenseNova) sensenova
别名 sensetime / sensechat / shangtang
api.sensenova.cn/compatible-mode/v1/chat/completions SenseChat-*
360 智脑 zhinao
别名 360 / qihoo / 360ai
api.360.cn/v1/chat/completions 360gpt*
华为云 ModelArts(盘古 / MaaS) modelarts
别名 huawei / maas / pangu
api.modelarts-maas.com/v1/chat/completions

海外主流平台

平台 protocol 取值 默认端点 模型名自动识别
OpenAI openai
别名 oai / openai-compatible / compatible / chat_completions
api.openai.com/v1/chat/completions gpt-*o3
Anthropic Claude claude
别名 anthropic / claude-messages / messages
api.anthropic.com/v1/messages claude-*
Google Gemini gemini
别名 google
generativelanguage.googleapis.com/v1beta/openai/chat/completions gemini-*
Z.ai(智谱国际站) zai
别名 z-ai / zhipu-global
api.z.ai/api/paas/v4/chat/completions
xAI(Grok) grok
别名 xai / x-ai / x.ai
api.x.ai/v1/chat/completions grok-*
Mistral AI mistral
别名 mistralai
api.mistral.ai/v1/chat/completions mistral-*codestral-*
Meta(Llama API) llama
别名 meta / meta-llama
api.llama.com/compat/v1/chat/completions
Cohere cohere
别名 command
api.cohere.ai/compatibility/v1/chat/completions command-*
Perplexity perplexity
别名 pplx / sonar
api.perplexity.ai/chat/completions sonar*
Azure OpenAI azure
别名 azure-openai / azureopenai
需自填base_url``

聚合中转平台

平台 protocol 取值 默认端点 模型名自动识别
OpenRouter openrouter
别名 or / open-router / open_router
openrouter.ai/api/v1/chat/completions
硅基流动(SiliconCloud) siliconflow
别名 silicon / siliconcloud / guiji
api.siliconflow.cn/v1/chat/completions
魔搭社区(ModelScope) modelscope
别名 moda / damo
api-inference.modelscope.cn/v1/chat/completions
Groq groq
别名 groqcloud
api.groq.com/openai/v1/chat/completions
Together AI together
别名 togetherai / together-ai
api.together.xyz/v1/chat/completions
Fireworks AI fireworks
别名 fireworksai
api.fireworks.ai/inference/v1/chat/completions
DeepInfra deepinfra api.deepinfra.com/v1/openai/chat/completions
Cerebras cerebras api.cerebras.ai/v1/chat/completions
NVIDIA NIM nvidia
别名 nim / nvidia-nim / build-nvidia
integrate.api.nvidia.com/v1/chat/completions

本地 / 自建部署

平台 protocol 取值 默认端点 模型名自动识别
Ollama(本地) ollama localhost:11434/v1/chat/completions
LM Studio(本地) lmstudio
别名 lm-studio
localhost:1234/v1/chat/completions
vLLM(自建) vllm
别名 sglang / xinference
localhost:8000/v1/chat/completions

表格由 $ai->listProtocols() / listProtocolGroups() 提供程序化版本,可直接渲染后台下拉框; $ai->listKnownModels('qwen') 返回该平台的常用模型清单(不发请求)。 别名只是同一协议的另一种写法,效果完全相同(protocol => 'kimi' 等价于 protocol => 'moonshot')。

内置模型标识(快捷方式)

下列模型标识可直接传给 model,无需 protocol,库会解析出平台、协议与端点:

平台 模型标识 实际协议 端点
OpenAI gpt-4.1 OpenAI api.openai.com
OpenAI gpt-4o OpenAI api.openai.com
Claude claude-3-opus Claude api.anthropic.com
Gemini gemini-2.5-pro Gemini(OpenAI 兼容端点) generativelanguage.googleapis.com
DeepSeek deepseek-chat OpenAI api.deepseek.com
DeepSeek deepseek-reasoner OpenAI api.deepseek.com
DeepSeek deepseek-v4-pro OpenAI api.deepseek.com
DeepSeek deepseek-v4-flash OpenAI api.deepseek.com
DeepSeek deepseek-anthropic Claude api.deepseek.com/anthropic
OpenRouter openai/gpt-4o 等完整标识 OpenRouter(OpenAI 兼容) openrouter.ai/api

deepseek-anthropic 是 DeepSeek 的 Anthropic 兼容端点,用 Claude 协议通信——需要工具调用(Agent)时用它,可以用 DeepSeek 的价格跑 Anthropic 的 tools 协议

表外的模型也能直接用

上表只是「开箱即用的快捷标识」,model 并不限于表内的值

模型名无法归属官方平台、又没给 base_url / endpoint 时,请求前会抛 ConfigException,而不是把 Key 发到不相干的官方域名。

protocol 除了上面平台表里的取值,还可以传实现了 Ai\Contracts\ProtocolInterface自定义协议类名(见「扩展开发」)。

不传 protocol 时按模型名推断(见平台表「模型名自动识别」列),也识别 厂商/模型 写法(如 qwen/qwen-max)。推断不出时按 openai 协议处理,此时必须给 base_urlendpoint

只对厂商自有模型名做推断llama3mixtral 这类被多家平台托管的开源模型名不参与推断(无法判断你想连哪一家),需要显式给 protocolbase_url

协议差异(重要)

各平台协议对 payload 键的支持并不一致,写业务代码前需要知道:

payload 键 OpenAI 协议 Claude 协议 Gemini 协议
messages ✅(role: system 会被丢弃)
system(顶层) ❌ 忽略 ❌ 忽略
tools / tool_choice ❌ 忽略 ❌ 忽略
temperature / max_tokens
stream ✅(自动附带 usage 统计)

结论:

protocol 平台 鉴权用的密钥
deepseek-anthropic(模型标识) DeepSeek deepseek__api_key
zhipu-anthropic 智谱 GLM zhipu__api_key
moonshot-anthropic 月之暗面 Kimi moonshot__api_key
qwen-anthropic 阿里云百炼 qwen__api_key

运行时查询平台与模型

真实用例——按平台分组拉取模型列表并本地缓存一周,供后台下拉框渲染:


配置项

setConfig()增量合并,可以分多次调用;每次传入 model 都会重建模型与协议实例。base_urlprotocol 等既可以和 model 一起传,也可以在设置模型之后再补。

生成参数(max_tokensmax_completion_tokenstemperaturetop_ptop_kstoppresence_penaltyfrequency_penaltyseedresponse_formatsystemtoolstool_choicereasoning_effortthinking)写在 setConfig() 里对所有请求生效,单次 chat() 的 payload 优先级更高;连接信息(api_keybase_url 等)不会进入请求体。

接口有私有参数时用 extra_body(直接并入请求体),需要特殊鉴权头时用 headers

链式接口:

调试时可用 $ai->getLastInfo() 获取最近一次请求的 cURL 信息(http_code、总耗时等)。

网络代理

支持 http://https://socks5://socks5h://(DNS 也走代理)、socks4://socks4a://

自定义接口地址(第三方转发 / 中转 / 自建网关)

默认端点是各平台的官方地址。要接入第三方转发、中转或自建网关,有两种配置方式,优先级从高到低:

1. base_url —— 接口根地址,与协议官方路径智能拼接(最常用)

只要给出根地址即可,库会补上协议对应的路径;根地址自带的路径前缀会保留,与官方路径重叠的片段自动去重:

base_url 协议路径 实际端点
https://proxy.com /v1/chat/completions https://proxy.com/v1/chat/completions
https://proxy.com/v1 /v1/chat/completions https://proxy.com/v1/chat/completions(重叠段去重)
https://proxy.com/openai /v1/chat/completions https://proxy.com/openai/v1/chat/completions
https://proxy.com/v1/chat/completions /v1/chat/completions 原样(已是完整端点)
127.0.0.1:8080 /v1/chat/completions https://127.0.0.1:8080/v1/chat/completions(缺 scheme 按 https)

2. endpoint —— 完整端点覆盖,原样使用(最灵活)

当接口路径结构与官方完全不同时使用,直接给出完整 URL:

endpoint 优先级高于 base_url;两者都不设置时使用官方默认端点,完全向后兼容。


OpenRouter 聚合中转

OpenRouter 是一个 AI 模型聚合平台,通过统一的 OpenAI 兼容接口访问 OpenAI、Claude、Gemini、DeepSeek、Llama 等多种模型。库已内置 openrouter 协议,开箱即用

OpenRouter 上的模型名使用 厂商/模型 格式,协议推断规则会自动提取厂商前缀:

OpenRouter 返回的 usage 字段是 OpenRouter 统计而非原始模型统计(可能包含缓存命中标记等扩展字段),$response->getUsage() 原样透传。

通过 OpenRouter 查看实时模型状态:


其他常见 AI 中转/聚合服务

OpenRouter、硅基流动、魔搭、Groq、Together、Fireworks、DeepInfra、NVIDIA NIM 已内置为协议(见「平台一览」),直接 protocol 指定即可。其余中转站与自建网关走 OpenAI 兼容协议(protocol=openai),配置 base_urlendpoint

以上所有接入方式均支持流式输出、附件、回调等完整功能。

模型列表端点listModels() 会跟随 base_url 走同一个网关;只配了 endpoint 时,库按对话端点同源推导(如 .../v1/chat/completions.../v1/models)。若网关的模型列表路径特殊,用 endpoint_models 单独完整覆盖(仅对 listModels() 生效)。OpenRouter 的模型列表接口返回完整定价数据,listModels(true) 可获取。

当前实际请求端点可随时查询:


Claude Code CLI 程序调用

Ai\Cli\ClaudeCode 直接调用本机安装的 claude 可执行程序(Claude Code CLI),与 Ai\Protocol\Claude(Anthropic HTTP API)互补。适合让 AI 直接操作工作区文件:读写文件、执行工具,配合 acceptEdits 权限模式实现"AI 改代码"。

快速开始

默认参数(均经实测验证):

--allowedTools--tools 语义不同:前者决定"哪些工具不用问",后者(setTools())决定"模型有哪些工具可用"。要真正限制能力范围用 setTools()setDisallowedTools()

claude 路径:自动检测 + 缓存 + 手动指定

自动检测顺序:command -v claude(PATH)→ 常见安装路径(~/.local/bin、Homebrew、/usr/bin)→ nvm 最新版本 ~/.nvm/versions/node/*/bin/claude → 登录 shell command -v。结果缓存到进程内 + 文件(默认 sys_get_temp_dir()/ai_claude_binary_cache.json),避免 PHP-FPM 下每次请求重复探测。

自定义 CLI 参数

所有 claude 参数均可覆盖/新增/删除:

参数名不区分下划线:setFlag('permission_mode', 'plan') 等价于 --permission-mode plan

多值参数会按 CLI 各自的解析规则渲染,无需自己拼串:setting-sources/tools/fallback-model 逗号连接,add-dir/mcp-config 一个 flag 跟多个值,plugin-dir/plugin-url 重复 flag。

注意claude CLI 没有 --working-dir--max-budget--proxy--theme 这些参数(实测会被拒绝)。工作目录用 setWorkdir()(内部转成 cd ... &&),代理走环境变量 HTTP_PROXY/HTTPS_PROXY

常用参数的专用方法

除了通用的 setFlag(),常用选项都有带取值校验的专用方法:

结构化输出

setJsonSchema() 约束模型最终必须输出符合 schema 的 JSON,getStructured() 直接拿数组:

流式调用(事件回调)

runStream() 逐事件回调,事件语义与官方 IDE 插件一致,可直接转发给 SSE:

result 事件是最终汇总:文本取自 result.result,费用取自 result.total_cost_usd(CLI 实测值,无需价格表),is_error:trueisSuccess() 返回 false

响应对象除 getContent() / getSessionId() / getCostUsd() 外还提供:getStructured()getThinking()getToolUses()getTools()getPermissionDenials()getSubtype()getStopReason()getInit()getNumTurns()getDurationMs()getExitCode()getCommand()

多轮会话续接

每次执行后若输出带新 session_id,会自动回写到内部,getSessionId() 始终是最新的。

自定义执行器(远程 / 容器化场景)

默认用 proc_open 本地执行。需要经 SSH/SFTP 在宿主机跑 claude 时(如 Docker 容器内 PHP),注入自定义执行器:

配套设置:

信息查询(版本 / 登录态 / 模型列表 / 额度用量)

不需要发起对话就能读取 CLI 侧的各类信息,不消耗模型额度

listModels()Ai\AI::listModels() 保持同样的约定:默认返回可直接使用的模型标识数组,传 true 返回完整数据,适合后台下拉框渲染。

额度查询

每项还含 severitynormal / 告警级别)、resets_at(ISO8601)、is_active。按订阅计费时 limit_dollars 类字段为 null,只提供百分比;额度不可用时返回空数组。

getUsage() 的完整结构:

说明
session 当前进程的 total_cost_usd、耗时、代码增删行数、分模型用量
subscription_type 订阅类型,如 max / pro
rate_limits 各限流窗口原始数据 + 归一化后的 limits 数组 + extra_usage 额度包信息
behaviors 近一天 / 一周的 request_countsession_count 等统计

在会话中查询ClaudeCodeSession 上同名方法会复用已运行的进程,因此 getUsage() 拿到的 session.total_cost_usd 就是本会话的真实累计花费;另有 getSessionCost() 返回同交互式 /cost 的文本报告。

CLI 的 get_context_usage(上下文窗口占用)只在交互式 UI 下响应,headless 模式不回包,故本库未提供对应方法。

常驻双工会话(ClaudeCodeSession)

Ai\Cli\ClaudeCodeSession 复刻官方 IDE 插件(VSCode / JetBrains)的进程工作方式:claude 以长驻进程运行,stdin 持续接收 JSON 消息,stdout 持续吐事件,工具权限通过 stdio 上的 control_request 协议实时回调给 PHP 决策。

插件实测启动参数:

本类默认采用其中与服务端场景相符的部分(双工 + stdio 权限回调 + 全设置源 + 消息回显 + 禁用 Chrome);权限模式保持更保守的 acceptEdits,思考预算和调试日志默认不开,需要时用 setThinkingTokens(31999) / setDebug() 打开。

与一次性模式的区别

ClaudeCode ClaudeCodeSession
进程 每轮起停一次 长驻,多轮共用
多轮 --resume 重放历史 上下文常驻内存
工具权限 靠 flag 静态配置 逐次回调 PHP 决策
中断 只能 kill 进程 interrupt() 优雅中断
运行时改配置 不支持 热切权限模式 / 模型 / 思考预算
受限 PHP 环境 支持自定义执行器(SSH) 仅本地 proc_open

中断与运行时控制

权限回调的边界(重要)

onPermission() 只会收到 CLI 认为"需要询问"的调用,它不是一道完整的拦截层。以下情况 CLI 自行放行、不问 PHP:

硬性禁止某个工具,用 setDisallowedTools(['Bash'])(工具从工具集移除,模型根本看不到)或 setTools([...]) 限定可用集合,不要只依赖回调。

未注册 onPermission() 时,默认只自动放行 Read / Edit / Write / Grep / Glob,其余一律拒绝;setAutoApproveTools([...]) 改名单,allowAllTools() 全部交回 CLI 自己判断。

其余会话方法:start() / isRunning() / close() / kill() / sendMessage($contentBlocks) / getInit() / getAvailableTools() / getCommand()ClaudeCode 的全部参数方法在会话类上同样可用(需在首次 send() 前设置)。

环境要求


流式输出(SSE)

调用 setStream(true) 后,chat() 会在接收模型数据的同时直接向输出缓冲区写 SSE 数据(自动设置响应头、关闭 Nginx 缓冲),无需注册回调:

服务端实际输出的报文格式(固定协议,前端按此解析):

对应的前端消费代码:

真实用例——后台聊天接口(含代理、附件、流式):

PHP 环境注意:流式输出会清空并关闭所有输出缓冲。如果使用会话锁(session_start()),建议在流式开始前 session_write_close(),否则同一用户的其它请求会被阻塞。

常驻内存框架(Swoole / Workerman):setStreamCallback()

上面的默认行为是 echo 到输出缓冲区,只适用于 PHP-FPM / CLI。在 Swoole、Workerman、RoadRunner 这类常驻内存框架里,echo 会落到进程标准输出(日志文件),永远送不到客户端。这种场景注册回调,由调用方自己下发:

注册回调后库不再产生任何输出,SSE 帧格式完全由调用方决定。事件结构:

字段 说明
type stream_chunk 增量分片 / stream_end 结束
content stream_chunk 的增量文本,已由协议层归一化,跨平台通用;无正文的分片为 null
raw stream_chunk 的平台原始分片数组,需要平台专有字段时才用
data stream_end 的汇总:content 完整正文、modelusage

nullsetStreamCallback(null))恢复默认的直接输出。

平台兼容性:40 个协议均已覆盖

「普通对话 + 流式输出 + token 统计」是每个协议的基础能力,tests/stream_test.php 用各平台真实的 SSE 报文逐个回放校验。三套测试都不联网、不需要 Key、不依赖 PHPUnit

CI 会在 PHP 7.1 / 7.2 / 7.4 / 8.0 / 8.2 / 8.4 上跑同样的检查,并在 8.2 上额外跑一次静态分析 与 PHP 7.1 兼容性扫描。最低版本 7.1 是真的把整套测试跑一遍,不是只做语法检查。

库内所有公开方法都带完整的 phpdoc 类型(PHP 7.1 不支持类型化属性,类型只能写在注释里), IDE 能正确补全 getToolCalls() 这类方法的返回结构。

覆盖的报文差异(都踩过坑,已在传输层统一处理):

差异 说明
data:不带空格 SSE 规范里冒号后的空格是可选的,讯飞星火等平台就不带;只认带空格的写法会导致整个流为空
CRLF 行尾 部分网关/代理会改写换行符
末尾无换行符 最后一帧(往往正是带 usage 的收尾帧)没有换行时不能被丢弃
夹杂 event: / id: 等字段 Anthropic 协议每帧都带 event:,需正确跳过
用量分帧下发 Anthropic 把 input_tokens 放在 message_startoutput_tokens 放在 message_delta,需跨帧合并
HTTP 200 但流里报错 MiniMax(base_resp)、OpenAI 系(error)等出错时状态码仍是 200,需抛异常而不是返回空内容

usage 中的 prompt_tokens / completion_tokens / total_tokens 三个标准字段在所有平台一致可用 (Anthropic 系的 input_tokens / output_tokens 已自动映射),平台特有字段原样保留。

流式下 getStopReason()getToolCalls() 同样可用:

自定义协议可选实现四个流式钩子(都不实现也能正常流式,只是拿不到对应信息):

钩子 作用
parseStreamUsage(array $chunk): ?array 该帧的 token 用量,AI 层逐帧合并
parseStreamError(array $chunk): ?string 该帧的错误信息,非空即抛异常
parseStreamStopReason(array $chunk): ?string 该帧的结束原因(已归一)
parseStreamToolCalls(array $chunk): ?array 该帧的工具调用分片,返回 [索引 => ['id'=>, 'name'=>, 'arguments'=>片段]],AI 层按索引拼接

附件(多模态)

附件格式由模型层适配:视觉模型(如 gpt-4o)转成各平台的图片块;不支持多模态的模型(如 DeepSeek 系列)会把附件信息以文本形式追加到最后一条用户消息,避免请求直接报错。

附件在每次 chat() 后自动清空,不会影响下一轮对话。


多轮对话上下文

两种方式,按需选一:

方式一:设 rounds,库自动维护(推荐)

rounds 默认为 0(不启用),此时库完全不碰历史,行为与旧版本一致。

多用户 / 常驻进程下用 setSessionId() 隔离上下文,一个 AI 实例可服务多个会话:

历史存在内存里,进程退出即失。跨请求要持久化就自己落库:

方法 说明
setSessionId(string) / getSessionId() 切换/读取当前会话,不同会话各自独立一份历史
getHistory() / setHistory(array) 读写当前会话的历史消息
clearHistory(bool $all = false) 清空当前会话;传 true 清空全部会话
exportHistory() / importHistory(array) 导出/导入全部会话,用于持久化

裁剪按「轮」而非按条数:一轮从一次真正的用户提问开始,只含 tool_result 的消息 算作上一轮工具调用的一部分。这样不会把 tool_use 和对应的 tool_result 切散—— 切散会让下一次请求直接被平台拒绝。

chatBatch() 不读写历史:批量里每条都是独立请求,混进同一份上下文没有意义。

方式二:自己维护 messages

不设 rounds 时库完全不介入,业务层自行拼接:

需要完全掌控裁剪策略(按 token 数、按重要性摘要等)时用这种方式。

请求前后回调

回调内抛出的异常会被捕获并记录到 error_log,不会中断主流程。


响应对象

chat() 返回 Ai\Contracts\AIResponseInterface

方法 说明
getContent(): string 回复文本(流式模式下为累积后的完整文本)
getRaw(): array 平台原始响应体(Agent 解析 tool_use 块靠它)
getUsage(): array 完整用量对象,含 prompt_tokens / completion_tokens / total_tokens 及平台返回的扩展字段(prompt_tokens_details.cached_tokenscache_creation_input_tokens 等,因平台而异)
tokens(): int 总 tokens
getModel(): string 实际返回的模型名
isSuccess(): bool 是否成功
cost(array $pricing): float 按价格表估算费用,默认每千 tokens(与旧版本一致,不改动已有代码的账)
costPerMillion(array $pricing): float 同上但按每百万 tokens,可直接抄官网数字,如 ['prompt'=>5.0,'completion'=>25.0,'cached'=>0.5]cached 为命中缓存的输入价,两大家族的字段名都认
getToolCalls(): array 模型发起的工具调用,已归一:[['id'=>..,'name'=>..,'input'=>[..]]]
hasToolCalls(): bool 本轮是否要求调用工具
getStopReason(): string 结束原因(已归一):end_turn / tool_use / max_tokens / content_filter / refusal
toAssistantMessage(): array 转成可回填进 messages 的 assistant 回合
getError(): string 失败原因(仅 chatBatch() 这类不抛异常的场景会填充)
toArray() / __toString() 转数组 / 直接当字符串用

异常处理

RequestException 由传输层抛出,chat() 内部会将其转成携带平台信息的 AIException,业务层通常只需捕获 AIException


健壮性:超时与自动重试

AI 接口最高频的失败不是「打不通」,而是 429 限流5xx 临时故障。库默认已处理:

情形 行为
408 / 409 / 429 / 500 / 502 / 503 / 504 / 529 自动重试
响应带 Retry-After(秒数或 HTTP 日期) 优先按服务端给的时间等待,并有上限保护
Retry-After 指数退避 + 抖动(避免多进程被同时限流后又齐刷刷重试)
4xx(除上表)如 400 / 401 / 403 不重试,立即抛异常
流式请求 不重试——分片已经吐给调用方,重试会造成重复输出
请求体含非 UTF-8 字节 立即抛 RequestException 并说明原因(此前会静默发出空请求体)

需要接入连接池、换 HTTP 客户端或在单元测试里注入假传输层时,替换整个传输层:

并发批量:chatBatch()

批量翻译、摘要、打标签这类场景串行跑,总耗时是「单条 × 条数」,且每条都要重做一次 TLS 握手。chatBatch()curl_multi 并发,总耗时约等于「最慢的一条 × 批次数」:

日志:接到你自己的日志系统

库内不再硬编码 error_log()。注入后拉取模型列表失败、流式回调异常等都会走你的日志:


Agent:工具调用循环

Ai\Agent\Agent 实现完整的 agentic 循环:模型决定调用哪个工具 → 库执行工具 → 结果回填给模型 → 继续,直到模型给出最终答复或达到迭代上限。

40 个协议全部可用。各家把同一件事写成了两套结构,库在协议层吃掉了差异:

OpenAI 系(36 个协议) Anthropic 系(4 个协议)
工具定义 {type:'function', function:{name, parameters}} {name, description, input_schema}
模型发起 message.tool_calls[]arguments 是 JSON 字符串 content 里的 tool_use 块,input数组
结果回填 独立的 {role:'tool', tool_call_id} 消息 user 消息里的 tool_result
结束原因 finish_reason: 'tool_calls' stop_reason: 'tool_use'
系统提示 messages 首条 role:'system' 顶层 system 字段

业务层只写一套(库的统一格式,采用 Anthropic 风格),换平台只改 protocol

完整可运行示例见 examples_agent.php;跨平台一致性由 tests/tools_test.php 保证。

流式跑 AgentsetStream(true) 后每轮正文实时吐给回调,工具调用照常工作—— 库会把各平台分片下发的 tool_calls 重组回来(OpenAI 系按 delta.tool_calls[].indexarguments 字符串,Anthropic 系按 content_block_start + input_json_delta 拼)。 适合聊天界面:用户能一边看模型说话,一边看它去调工具。

Agent 只是临时借用你的 AI 实例:跑完会把 setStream() 恢复原状(异常路径也会), 不会影响后续无关的 chat()

也可以直接写 OpenAI 原生格式({type:'function'} 的工具定义、role:'tool' 的消息), 库会识别并转成目标平台的结构,不强制迁移已有代码。

不用 Agent,自己控制循环

AIResponse 提供了平台无关的取用接口:

工具定义

handler 返回的字符串会作为 tool_result 回填给模型;抛出的异常会被自动转成 ERROR: 异常信息 交给模型,不会中断循环。

运行

事件类型

onEvent() 回调会依次收到:

事件 字段 含义
thinking iter 第几轮迭代开始
agent_text text 模型输出的自然语言
tool_call nameinput 模型决定调用某工具
done 正常结束
error message 出错或达到最大迭代步数

工具内部的细粒度事件(如 diff、进度)由各 handler 自行通过闭包发出,库不做假设。


Editor:AI 代码编辑

Ai\Editor\* 提供一套「让 AI 改代码」的完整协议:把编辑器现场(当前文件、光标、选区、已打开文件、工作区规范)结构化后交给模型,模型返回可校验、可执行的编辑动作。

json\n{$ctxJson}\n

配合 Agent 可实现三种工作模式:plan(只读规划)、approval(产出待人工审核的建议)、auto(自动写入并备份)。


联网搜索

不少平台的模型能自己上网查资料再回答。各家的开关五花八门——有的是请求体顶层的一个布尔值, 有的要往 tools 里塞一个内置工具,还有的走插件系统。本库把它们归一成一个 search 配置:

换个平台只改 modelsearch 这行不动:

细化配置

search 传数组可以调细节。省略 enable 即视为开启:

平台不支持的细项会被静默忽略,不影响搜索本身开启。这是刻意的:统一层承诺的是 「搜索会开」,不是「每个细节都能在每个平台生效」。下表是各项的实际落点:

统一配置 Claude 通义千问 智谱 GLM Kimi 文心一言 OpenRouter Perplexity
max_uses max_uses
count count search_number max_results
query search_query
recency search_recency_filter search_recency_filter
forced forced_search require_search
citation 总是开 enable_citation enable_citation
sources enable_source search_result enable_trace return_related_questions
allowed_domains 仅首个 include_domains
blocked_domains exclude_domains - 前缀

几处需要留意的差异:

哪些平台支持

没列进来的平台,配了 search 会直接抛 ConfigException,而不是静默忽略。 静默忽略在这里是最糟的选择:用户拿到的是一个「答得挺像样、但其实没上网」的回复, 内容陈旧却毫无征兆,往往要等到发现模型说的是去年的事才察觉。

需要特别说明的两个:

平台私有参数:用 extra_body

统一配置只收各家都有的语义,平台独有的参数(通义的 search_strategy、 智谱的 search_engine、OpenRouter 的 engine 等)不进 search,用 extra_body 直接写:

extra_body 在请求体顶层做合并,同名字段会整体覆盖 search 生成的结果—— 上例中最终发出的 search_options 只有 search_strategyforced_search 会被顶掉。 要同时用两者,把所有子字段都写进 extra_body

库对某平台的判断有误或过时时,extra_body 也是逃生口:它绕过全部声明检查, 可以直接发平台原生的搜索参数。

Ai\Tools\HttpFetch 的区别

两者都能让模型用上网页内容,但不是一回事:

search 配置 Ai\Tools\HttpFetch(见下一节)
谁在联网 平台的服务器 你的 PHP 进程
计费 平台按次收搜索费 只有 token 费用,流量走你的服务器
能力 搜索引擎检索 抓取你指定的 URL
可控性 只能给过滤条件 完全可控,含 SSRF 防护
支持范围 仅上表 7 个平台 所有平台

需要「模型自己决定搜什么」用 search;需要「读这几个我指定的页面」用 HttpFetch。 两者可以同时开。


Tools:安全网页抓取

让模型联网读网页时,最大的风险是 SSRF。Ai\Tools\HttpFetch 内置纵深防御:

把它包成 Agent 工具即可让模型自主上网:


Memory:Agent 长期记忆

把一个 Markdown 文件当作 Agent 的持久记忆(类似 CLAUDE.md)。文件位置由业务层决定,库不认识任何具体路径。


完整业务案例:批量 JSON 翻译

一个真实场景——把多语言词条按批交给 AI 翻译,要求模型严格返回 {"记录ID":"译文"} 的 JSON,并做失败重试、格式校验与结果回写。

json (json)?\s(.+?)\s

实战经验:

当前模型使用的协议不支持「图像生成」能力。本协议目前只支持对话(chat)

未指定实时通道协议。当前平台的语音能力只能通过 WebSocket 访问, 请显式调用 ->useWebSocket() 启用。……

提交 POST /v1/video_generation → task_id 查询 GET /v1/query/video_generation → status=Success,但只给 file_id 再取 GET /v1/files/retrieve → 真正的下载地址(有效期 9 小时)



库内自动走完三步,调用方感知不到差别。另外 MiniMax 的失败**不体现在 HTTP 状态码上**——
`base_resp.status_code` 非 0 才是失败,此时 HTTP 仍是 200,库内会检查这个字段。

#### 支持的平台与模型

| 平台 | 模型(据官方文档) |
|------|------|
| 通义万相 | `wan2.7-t2v`、`wan2.7-t2v-2026-06-12` |
| 智谱 | `cogvideox-3`、`cogvideox-2`、`cogvideox-flash`、`viduq1-*`、`vidu2-*` |
| 火山方舟 | Seedance 系列 |
| MiniMax | `MiniMax-Hailuo-2.3`、`MiniMax-Hailuo-02`、`T2V-01-Director`、`T2V-01` |
| Gemini | `veo-3.1-generate-preview`、`veo-3.1-lite-generate-preview`、`gemini-omni-flash` |
| Z.ai | 视频生成(据 z.ai 文档) |

⚠️ **结果 URL 都有有效期**(万相约 24 小时、MiniMax 仅 9 小时),
存 URL 进库很快就会失效,必须及时 `saveTo()` 落地。

### 媒体结果要及时落地

多数平台返回的图片/视频 URL **有效期只有几小时到 24 小时**,
只把 URL 存进库,第二天就会全部失效。用 `saveTo()` 及时取回:

下载走库内带 SSRF 防护的抓取器(IP 钉死、逐跳重校验),不是裸 `file_get_contents()`。
目标目录**必须已存在**——库不会自动创建,避免路径写错时在磁盘上散落一堆空目录。

### WebSocket 通道默认关闭

讯飞等平台的语音能力只提供 WebSocket。本库已集成,
但**必须显式启用**,因为 WS 是长连接,超时与错误语义都和普通 HTTP 请求不同:

不启用直接调用会得到明确提示,而不是含糊的连接失败。

### 自定义网关

把 `base_url` 指向自建网关或中转服务时,图像/语音端点会**自动跟着走同一个网关**,
不会回落到官方地址(那意味着把数据发到你没指定的服务器上)。
需要单独指定某个能力的完整地址时,用 `<能力名>_endpoint` 配置项:

这个配置项同时是**逃生口**:库对某平台能力的判断有误或过时时,配上
`<能力名>_endpoint` 就能绕过声明检查。若该协议族本身没有对应形态的解析器
(比如 Claude 之于图像),仍会报错,但会点明是哪一层挡住的,并建议改用
`protocol` + `base_url`。

### 给自定义协议类的迁移说明

`ProtocolInterface` 在 v1.14.0 新增了 4 个能力方法。

- **继承内置协议的(`extends OpenAI` / `extends Claude` 等):无需任何改动。**
  README「扩展开发」一节教的就是这种写法,库内 38 个厂商协议类也都是这么写的。
- **裸实现接口的(`implements ProtocolInterface`):加一行即可。**

---

## 已知限制

- 会话历史存在内存里,进程退出即失,跨请求需用 `exportHistory()` / `importHistory()` 自行落库;
- 流式下的工具调用已支持(分片会自动重组)。若模型声明本轮要调工具、却一个都重组不出来(说明该平台用了本库尚未覆盖的分片结构),会抛 `stream_tool_calls_unassembled` 异常而非静默返回空响应;
- 流式输出只提取正文增量,推理模型的思维链(`reasoning_content` / `thinking` 块)不计入 `getContent()`,需要时从 `stream_chunk` 事件的 `raw` 字段自取;
- 各平台的 `knownModels()` 常用模型清单是库内维护的静态快照,仅用于离线渲染下拉框与拉取失败兜底,最新可用模型请以 `listModels()` 的实时结果为准;
- Azure OpenAI 只覆盖了新版 `/openai/v1` 路由,旧版「部署名 + api-version」路由需自行用 `endpoint` 配置完整 URL;AWS Bedrock、Google Vertex AI 因需要 SigV4 / OAuth 签名,暂未内置;
- 自定义模型的 `supports()` 能力是乐观默认值(对方接口实际支持什么库无从得知),需要准确值时用 `features` 配置项自行声明;
- `Ai\Protocol\Gemini::convertMessages()` 未被调用——Gemini 走的是 OpenAI 兼容端点,消息直接透传;
- `chatBatch()` 并发批量不支持流式,也不走 `setAttachments()`(附件请写在各自 payload 里);
- `cost()` 需自行传入价格表,库不内置各平台价格(价格变动频繁,内置必然过期);
- `Ai\Cli\ClaudeCode` 依赖本机已安装 claude 程序;`proc_open` / `shell_exec` 被禁用的受限 PHP 环境需改用自定义执行器(如 SSH/SFTP)。
- 视频生成只覆盖**文生视频与首帧图生视频**;
- 图像编辑只覆盖走 `/images/edits` 的平台;硅基流动与通义的图生图形态不同,未接入;
- `wait()` 是阻塞的,只适合 CLI 与队列 worker;Web 请求里请用「提交存库 + 定时任务轮询」的写法;
- WebSocket 通道只做「一次会话、发完收完就关」这一种模式,够覆盖讯飞 TTS/ASR;不支持并发多连接、自动重连、服务端模式与 permessage-deflate 压缩扩展;
- MiniMax 的语音识别形态与 OpenAI 差异较大,暂未接入;
- 向量化默认不分批,超出平台单次上限时需自行传 `batch_size`——各平台上限差异大且文档未必写明,库不预设一个「保险的小值」,那会让本可一次发完的平台白白多发几十个请求;
- 视频生成一律异步,`AsyncTask::wait()` 会阻塞,不可在 Web 请求中使用;跨请求恢复需自行把 `toArray()` 的结果落库;
- 火山方舟的视频模型清单与阶跃星辰的 ASR/音色清单**刻意留空**:其文档站是 JS 渲染的,未能查证。留空会回退到平台自己的模型列表接口,填错则会让用户拿着不存在的模型名去调。

---

## 许可证

MIT License

All versions of php-ai with dependencies

PHP Build Version
Package Version
Requires php Version >=7.1
ext-curl Version *
ext-json Version *
ext-mbstring Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package likun-mci/php-ai contains the following files

Loading the files please wait ...