主题
Ollama
Ollama 能在你本地机器上运行决策模型,例如 Nimble、Tev1 与 Clef,无需 API 密钥、无每次请求费用。OllamaDecisionModel 在 Ollama 的 System One API(POST /v1/systemone, 需 Ollama v0.35.0 或更新版本)之上实现了 DecisionModel API。
NOTE
本集成尚处于实验阶段,未来版本可能变化。
Maven 依赖
xml
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama</artifactId>
<version>1.23.0</version>
</dependency>用量
先下载一个决策模型:
shell
ollama pull nimble然后:
java
DecisionModel decisionModel = OllamaDecisionModel.builder()
.baseUrl("http://localhost:11434")
.modelName("nimble")
.build();
DecisionRequest request = DecisionRequest.builder()
.input("Help! My payouts have been failing for 3 days and nobody answers my emails.")
.question("team", ChoiceQuestion.builder()
.text("Which team should handle this ticket?")
.option("billing", "Payments, payouts, invoices, refunds")
.option("support", "Problems using the product")
.option("sales", "Pricing, upgrades, new accounts")
.build())
.question("urgent", YesNoQuestion.of("Does this need attention today?"))
.build();
DecisionResponse response = decisionModel.decide(request);
response.choice("team").value(); // "billing"
response.yesNo("urgent").probability(); // 0.97必须设置模型名,可在 builder 上或每次请求上设置。未下载的模型 会被 Ollama 拒绝,请求会以 ModelNotFoundException 失败。
没有 GPU,或 Ollama 正在加载模型时,一次请求可能耗时数秒,因此考虑更长的 timeout(...)。Ollama 在 5 分钟无请求后会卸载模型(除非在服务器上另有配置): 要让它更久保持加载,用秒设置 keepAlive(...),或设为负值以保持加载。其他设置还有 httpClientBuilder、maxRetries、logRequests、logResponses、logger、customHeaders 与 listeners。
decide() 与 decideAsync() 均受支持。
输入
输入可以是:
- 文本;
- 一个由命名值组成的
Map,它以 JSON 对象发送; - 一个由
TextContent与ImageContent组成的列表,其中的文本以空行拼接。
整个输入必须能装进模型加载时所用的上下文窗口(它取决于模型以及 Ollama 服务器的配置):Ollama 从不截断它。请求体最大不得超过 64 KiB,含图像时为 32 MiB。
图像
具备视觉能力的模型,例如 Clef 与 Clef Flash (Ollama v0.35.1 或更新版本),能判断 PNG、JPEG 与 WebP 图像:
java
DecisionModel decisionModel = OllamaDecisionModel.builder()
.baseUrl("http://localhost:11434")
.modelName("clef-flash")
.build();
DecisionRequest request = DecisionRequest.builder()
.input(List.of(
TextContent.from("The customer says the package arrived like this."),
ImageContent.from(base64Image, "image/jpeg")))
.question("damaged", YesNoQuestion.of("Is the item visibly damaged?"))
.build();Ollama 将图像与输入的其余部分分开接收,因此输入中每张图像会被它在图像序列中的 位置所替代:上面的输入会被发送为 The customer says the package arrived like this. 后接 [image 1]。 在 Map 中,图像也以同样方式被替代,从而其名称表明它是什么: Map.of("comment", comment, "photo", ImageContent.from(...)) 被发送为 {"comment": "...", "photo": "[image 1]"}。图像按其在输入中出现的顺序、跨 Map 的所有取值从 1 开始编号, 因此问题可以引用它们,例如 "Does [image 2] show the same item as [image 1]?"。这一 [image N] 约定来自 LangChain4j,而非 Ollama。
图像可作为 base64 数据给出,或通过 http、https 或 file URL 给出,此时它们会由你的应用在发送请求前 在调用线程上下载或读取(对 decideAsync() 亦然)。不支持 data: URL。其他内容,例如音频, 会在调用 Ollama 前以 UnsupportedFeatureException 拒绝。
::: caution 不要传入来自不可信来源的图像 URL,例如来自用户、工具或检索内容:你的应用 会下载任意 http URL 并读取任意本地 file URL,并把内容发送给 Ollama。请自行下载并核验此类 图像,再以 base64 数据传入。 :::
问题与答案
DecisionModel | Ollama | 备注 |
|---|---|---|
YesNoQuestion | noul | 当 yesWhen 与 noWhen 都设置时作为判据发送;只设置其一时则将其追加到问题后(例如 Answer yes when: ...) |
ChoiceQuestion | choice | 选项连同其描述发送 |
ScaleQuestion | score | 各等级以文本发送,带描述时为 label: description |
是/否答案包含"是"的概率。选择与量表答案包含每个选项或等级的概率,以及一个置信度。
一次请求最多可有 64 个问题。量表问题可有 2 到 10 个等级,选择问题至少需要 2 个选项;最大选项数取决于模型(例如 Tev1 为 26)。
由于这些限制,当工具超过 64 个时,请在工具选择组件上设置 maxToolsPerDecisionRequest(64); 而对于重排序,请调低 maxSegmentsPerRequest(...),以便 一次请求的片段能装进上下文窗口。
response.tokenUsage() 上报由 Ollama 统计的输入与输出词元。
无论模型为何,OllamaDecisionModel 都会将 ModelProvider.OLLAMA 作为其提供者上报,例如在监听器 与指标中。
从 TypeSafeDecisionModel 切换
Ollama 的决策模型也可用 TypeSafeDecisionModel 配合自定义 base URL 来调用,但 Ollama 会拒绝其中一些请求,例如带描述的量表等级,且它 不支持图像。要切换到 OllamaDecisionModel,只需替换类名:base URL 与模型名保持不变。此后监听器与指标 会将 OLLAMA 而非 TYPESAFE 上报为提供者。