LLM
wippy/llm 模块提供了统一的接口,用于与多个提供商(OpenAI、Anthropic、Google、本地模型)的大语言模型进行交互。支持文本生成、工具调用、结构化输出、向量嵌入和流式传输。
将模块添加到项目中:
wippy add wippy/llmwippy install在 _index.yaml 中声明依赖。LLM 模块需要环境存储(用于 API 密钥)和进程宿主:
version: "1.0"namespace: app
entries: - name: os_env kind: env.storage.os
- name: processes kind: process.host lifecycle: auto_start: true
- name: dep.llm kind: ns.dependency component: wippy/llm version: "*" parameters: - name: env_storage value: app:os_env - name: process_host value: app:processesenv.storage.os 条目将操作系统环境变量暴露给 LLM 提供商。将 API 密钥设置为环境变量(例如 OPENAI_API_KEY、ANTHROPIC_API_KEY)。
在条目中导入 llm 库并调用 generate():
entries: - name: ask kind: function.lua source: file://ask.lua method: handler imports: llm: wippy.llm:llmlocal llm = require("llm")
local function handler() local response, err = llm.generate("What are the three laws of robotics?", { model = "gpt-4o" })
if err then return nil, err end
return response.resultend
return { handler = handler }generate() 的第一个参数可以是字符串提示词、提示词构建器或消息表。第二个参数是选项表。
| 选项 | 类型 | 说明 |
|---|---|---|
model | string | 模型名称或类别(必填) |
temperature | number | 随机性控制,0-1 |
max_tokens | number | 最大生成令牌数 |
top_p | number | 核采样参数 |
top_k | number | Top-k 过滤 |
thinking_effort | number | 思考深度 0-100(具有思考能力的模型) |
tools | table | 工具定义数组 |
tool_choice | string | "auto"、"none"、"any" 或工具名称 |
stream | table | 流式配置:{ reply_to, topic, buffer_size } |
timeout | number | 请求超时秒数(默认 600) |
| 字段 | 类型 | 说明 |
|---|---|---|
result | string | 生成的文本内容 |
tokens | table | 令牌用量:prompt_tokens、completion_tokens、thinking_tokens、total_tokens |
finish_reason | string | 生成停止原因:"stop"、"length"、"tool_call"、"filtered"、"error" |
tool_calls | table? | 工具调用数组(如果模型调用了工具) |
metadata | table | 提供商特定的元数据 |
usage_record | table? | 使用量跟踪记录 |
提示词构建器
Section titled “提示词构建器”对于多轮对话和复杂提示词,使用提示词构建器:
imports: llm: wippy.llm:llm prompt: wippy.llm:promptlocal llm = require("llm")local prompt = require("prompt")
local conversation = prompt.new()conversation:add_system("You are a helpful assistant.")conversation:add_user("What is the capital of France?")
local response, err = llm.generate(conversation, { model = "gpt-4o", temperature = 0.7, max_tokens = 500})| 方法 | 说明 |
|---|---|
prompt.new() | 创建空构建器 |
prompt.with_system(content) | 创建带系统消息的构建器 |
:add_system(content, meta?) | 添加系统消息 |
:add_user(content, meta?) | 添加用户消息 |
:add_assistant(content, meta?) | 添加助手消息 |
:add_developer(content, meta?) | 添加开发者消息 |
:add_message(role, content_parts, name?, meta?) | 添加指定角色和内容部分的消息 |
:add_function_call(name, args, id?) | 添加助手的工具调用 |
:add_function_result(name, result, id?) | 添加工具执行结果 |
:add_cache_marker(id?) | 标记缓存边界(Claude 模型) |
:get_messages() | 获取消息数组 |
:build() | 获取用于 llm.generate() 的 { messages = ... } 表 |
:clone() | 深拷贝构建器 |
:clear() | 清除所有消息 |
所有 add_* 方法均返回构建器自身,支持链式调用。
通过追加消息来构建跨轮次的上下文:
local conversation = prompt.new()conversation:add_system("You are a helpful assistant.")
-- first turnconversation:add_user("What is Lua?")local r1 = llm.generate(conversation, { model = "gpt-4o" })conversation:add_assistant(r1.result)
-- second turn with full contextconversation:add_user("What makes it different from Python?")local r2 = llm.generate(conversation, { model = "gpt-4o" })在单条消息中组合文本和图像:
local conversation = prompt.new()conversation:add_message(prompt.ROLE.USER, { prompt.text("What's in this image?"), prompt.image("https://example.com/photo.jpg")})| 函数 | 说明 |
|---|---|
prompt.text(content) | 文本内容部分 |
prompt.image(url, mime_type?) | 来自 URL 的图像 |
prompt.image_base64(mime_type, data) | Base64 编码的图像 |
| 常量 | 值 |
|---|---|
prompt.ROLE.SYSTEM | "system" |
prompt.ROLE.USER | "user" |
prompt.ROLE.ASSISTANT | "assistant" |
prompt.ROLE.DEVELOPER | "developer" |
prompt.ROLE.FUNCTION_CALL | "function_call" |
prompt.ROLE.FUNCTION_RESULT | "function_result" |
prompt.ROLE.CACHE_MARKER | "cache_marker" |
克隆构建器以创建变体,而不修改原始构建器:
local base = prompt.new()base:add_system("You are a helpful assistant.")
local conv1 = base:clone()conv1:add_user("What is AI?")
local conv2 = base:clone()conv2:add_user("What is ML?")使用进程通信实时流式传输响应。需要 process.lua 条目:
local llm = require("llm")
local TOPIC = "llm_stream"
local function main() local stream_ch = process.listen(TOPIC)
local response = llm.generate("Write a short story", { model = "gpt-4o", stream = { reply_to = process.pid(), topic = TOPIC, }, })
while true do local chunk, ok = stream_ch:receive() if not ok then break end
if chunk.type == "chunk" then io.write(chunk.content) elseif chunk.type == "thinking" then io.write(chunk.content) elseif chunk.type == "error" then io.print("Error: " .. chunk.error.message) break elseif chunk.type == "done" then break end end
process.unlisten(stream_ch)end| 类型 | 字段 | 说明 |
|---|---|---|
"chunk" | content | 文本内容片段 |
"thinking" | content | 模型思考过程 |
"tool_call" | name、arguments、id | 工具调用 |
"error" | error.message、error.type | 流错误 |
"done" | meta | 流传输完成 |
process.lua 条目,因为它使用 Wippy 的进程通信系统(process.pid()、process.listen())。
将工具定义为内联模式并传递给 generate():
local llm = require("llm")local prompt = require("prompt")local json = require("json")
local tools = { { name = "get_weather", description = "Get current weather for a location", schema = { type = "object", properties = { location = { type = "string", description = "City name" }, }, required = { "location" }, }, },}
local conversation = prompt.new()conversation:add_user("What's the weather in Tokyo?")
local response = llm.generate(conversation, { model = "gpt-4o", tools = tools, tool_choice = "auto",})
if response.tool_calls and #response.tool_calls > 0 then for _, tc in ipairs(response.tool_calls) do -- execute the tool and get a result local result = { temperature = 22, condition = "sunny" }
-- add the exchange to the conversation conversation:add_function_call(tc.name, tc.arguments, tc.id) conversation:add_function_result(tc.name, json.encode(result), tc.id) end
-- continue generation with tool results local final = llm.generate(conversation, { model = "gpt-4o" }) print(final.result)end工具调用字段
Section titled “工具调用字段”| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 唯一调用标识符 |
name | string | 工具名称 |
arguments | table | 匹配模式的已解析参数 |
| 值 | 行为 |
|---|---|
"auto" | 模型决定何时使用工具(默认) |
"none" | 从不使用工具 |
"any" | 必须使用至少一个工具 |
"tool_name" | 必须使用指定的工具 |
生成匹配模式的已验证 JSON:
local llm = require("llm")
local schema = { type = "object", properties = { name = { type = "string" }, age = { type = "number" }, hobbies = { type = "array", items = { type = "string" }, }, }, required = { "name", "age", "hobbies" }, additionalProperties = false,}
local response, err = llm.structured_output(schema, "Describe a fictional character", { model = "gpt-4o",})
if not err then print(response.result.name) print(response.result.age)endrequired 数组中。对于可选字段使用联合类型:type = {"string", "null"}。设置 additionalProperties = false。
模型定义为带有 meta.type: llm.model 的注册表条目:
entries: - name: gpt-4o kind: registry.entry meta: name: gpt-4o type: llm.model title: GPT-4o comment: OpenAI's flagship model capabilities: - generate - tool_use - structured_output - vision class: - balanced priority: 100 max_tokens: 128000 output_tokens: 16384 pricing: input: 2.5 output: 10 providers: - id: wippy.llm.openai:provider provider_model: gpt-4o模型条目字段
Section titled “模型条目字段”| 字段 | 说明 |
|---|---|
meta.name | API 调用中使用的模型标识符 |
meta.type | 必须为 llm.model |
meta.capabilities | 功能列表:generate、tool_use、structured_output、embed、thinking、vision、caching |
meta.class | 类别归属:fast、balanced、reasoning 等 |
meta.priority | 基于类别解析的数值优先级(越高越优先) |
max_tokens | 最大上下文窗口 |
output_tokens | 最大输出令牌数 |
pricing | 每百万令牌成本:input、output |
providers | 包含 id(提供商条目)和 provider_model(提供商特定模型名称)的数组 |
对于本地托管的模型(LM Studio、Ollama),定义一个带有自定义 base_url 的单独提供商条目:
- name: local_provider kind: registry.entry meta: name: ollama type: llm.provider title: Ollama Local driver: id: wippy.llm.openai:driver options: api_key_env: none base_url: http://127.0.0.1:11434/v1
- name: local-llama kind: registry.entry meta: name: local-llama type: llm.model title: Local Llama capabilities: - generate max_tokens: 4096 output_tokens: 4096 pricing: input: 0 output: 0 providers: - id: app:local_provider provider_model: llama-3.2模型可以通过精确名称、类别或显式类别前缀引用:
-- exact model namellm.generate("Hello", { model = "gpt-4o" })
-- model class (picks highest priority in that class)llm.generate("Hello", { model = "fast" })
-- explicit class syntaxllm.generate("Hello", { model = "class:reasoning" })解析顺序:
- 按精确
meta.name匹配 - 按类别名称匹配(
meta.priority最高者优先) - 使用
class:前缀时,仅在该类别中搜索
在运行时查询可用模型及其能力:
local llm = require("llm")
-- all modelslocal models = llm.available_models()
-- filter by capabilitylocal tool_models = llm.available_models("tool_use")local embed_models = llm.available_models("embed")
-- list model classeslocal classes = llm.get_classes()for _, c in ipairs(classes) do print(c.name .. ": " .. c.title)end生成用于语义搜索的向量嵌入:
local llm = require("llm")
-- single textlocal response = llm.embed("The quick brown fox", { model = "text-embedding-3-small", dimensions = 512,})-- response.result is a float array
-- multiple textslocal response = llm.embed({ "First document", "Second document",}, { model = "text-embedding-3-small" })-- response.result is an array of float arrays在发送任务前探测提供商。适用于就绪性检查和轻量级健康监控:
local status, err = llm.status({ model = "gpt-4o",})| 选项 | 说明 |
|---|---|
model | 必填。要检查的模型。 |
provider_id | 可选。跳过模型解析,直接指向特定提供商。 |
返回提供商的 StatusResponse(内容取决于提供商)。
错误作为第二个返回值返回。发生错误时,第一个返回值为 nil:
local response, err = llm.generate("Hello", { model = "gpt-4o" })
if err then io.print("Error: " .. tostring(err)) returnend
io.print(response.result)| 常量 | 说明 |
|---|---|
llm.ERROR_TYPE.INVALID_REQUEST | 请求格式错误 |
llm.ERROR_TYPE.AUTHENTICATION | API 密钥无效 |
llm.ERROR_TYPE.RATE_LIMIT | 超出提供商速率限制 |
llm.ERROR_TYPE.SERVER_ERROR | 提供商服务器错误 |
llm.ERROR_TYPE.CONTEXT_LENGTH | 输入超出上下文窗口 |
llm.ERROR_TYPE.CONTENT_FILTER | 内容被安全系统过滤 |
llm.ERROR_TYPE.TIMEOUT | 请求超时 |
llm.ERROR_TYPE.MODEL_ERROR | 模型无效或不可用 |
| 常量 | 说明 |
|---|---|
llm.FINISH_REASON.STOP | 正常完成 |
llm.FINISH_REASON.LENGTH | 达到最大令牌数 |
llm.FINISH_REASON.CONTENT_FILTER | 内容被过滤 |
llm.FINISH_REASON.TOOL_CALL | 模型进行了工具调用 |
llm.FINISH_REASON.ERROR | 生成过程中出错 |
| 常量 | 说明 |
|---|---|
llm.CAPABILITY.GENERATE | 文本生成 |
llm.CAPABILITY.TOOL_USE | 工具/函数调用 |
llm.CAPABILITY.STRUCTURED_OUTPUT | JSON 结构化输出 |
llm.CAPABILITY.EMBED | 向量嵌入 |
llm.CAPABILITY.THINKING | 扩展思考 |
llm.CAPABILITY.VISION | 图像理解 |
llm.CAPABILITY.CACHING | 提示词缓存 |
- 智能体 - 带有工具、委托和记忆的智能体框架
- 构建 LLM 智能体 - 分步教程
- 框架概述 - 框架模块用法