langfuse-ruby 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/PROMPT_TROUBLESHOOTING.md +206 -0
- data/README.md +3 -3
- data/{CHANGELOG.md → docs/CHANGELOG.md} +2 -2
- data/{PUBLISH_GUIDE.md → docs/PUBLISH_GUIDE.md} +6 -6
- data/docs/README.md +33 -0
- data/langfuse-ruby.gemspec +12 -7
- data/lib/langfuse/client.rb +45 -15
- data/lib/langfuse/evaluation.rb +9 -8
- data/lib/langfuse/prompt.rb +2 -2
- data/lib/langfuse/version.rb +1 -1
- data/lib/langfuse.rb +14 -10
- data/scripts/release.sh +2 -2
- data/scripts/verify_release.rb +2 -2
- metadata +16 -12
- /data/{FINAL_SUMMARY.md → docs/FINAL_SUMMARY.md} +0 -0
- /data/{PROJECT_SUMMARY.md → docs/PROJECT_SUMMARY.md} +0 -0
- /data/{RELEASE_CHECKLIST.md → docs/RELEASE_CHECKLIST.md} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d97c16de061cdf52403a05086a90aaac149b9fe9dc6d771e36709e763abcb3eb
|
4
|
+
data.tar.gz: c254257501aff83671377cc50ea8f25c143d8dca6fa0f40d157fcfa6eb3d75b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2cf7c8a6d72bb5a81b73ba6a5a110e9e6312b09e9a790a14d566a41b1e7d4a8ce40c53fb8d0d74b4c12c9cd06bd20e03680b6829505f69aa7b80dee3ecf6750
|
7
|
+
data.tar.gz: c880f859cf2f0d6fc9586ceada7c7488ff25a8be4c3fbf4740443477e592b8eee20895e24c69c371a8f0a96c60fd40d1a66de2126b762378ea41115665de3666
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,206 @@
|
|
1
|
+
# Langfuse Ruby SDK - Prompt 获取故障排除指南
|
2
|
+
|
3
|
+
## 问题描述
|
4
|
+
|
5
|
+
当调用 `client.get_prompt("prompt-name")` 时,可能会遇到以下错误:
|
6
|
+
|
7
|
+
```
|
8
|
+
JSON::ParserError: unexpected token at '<!DOCTYPE html>
|
9
|
+
```
|
10
|
+
|
11
|
+
## 问题原因
|
12
|
+
|
13
|
+
这个错误通常表示 Langfuse API 返回了 HTML 页面而不是预期的 JSON 响应。最常见的原因是:
|
14
|
+
|
15
|
+
1. **404 错误**:请求的 prompt 不存在
|
16
|
+
2. **认证问题**:API 密钥无效或权限不足
|
17
|
+
3. **网络问题**:无法连接到 Langfuse 服务器
|
18
|
+
|
19
|
+
## 解决方案
|
20
|
+
|
21
|
+
### 1. 检查 Prompt 是否存在
|
22
|
+
|
23
|
+
首先确认要获取的 prompt 是否已在 Langfuse 中创建:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# 尝试获取 prompt
|
27
|
+
begin
|
28
|
+
prompt = client.get_prompt("your-prompt-name")
|
29
|
+
puts "成功获取 prompt: #{prompt.name}"
|
30
|
+
rescue Langfuse::ValidationError => e
|
31
|
+
if e.message.include?("404")
|
32
|
+
puts "Prompt 不存在,请先创建它"
|
33
|
+
else
|
34
|
+
puts "其他验证错误: #{e.message}"
|
35
|
+
end
|
36
|
+
rescue => e
|
37
|
+
puts "未知错误: #{e.message}"
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
### 2. 创建测试 Prompt
|
42
|
+
|
43
|
+
如果 prompt 不存在,可以先创建一个:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# 创建一个测试 prompt
|
47
|
+
test_prompt = client.create_prompt(
|
48
|
+
name: "test-prompt",
|
49
|
+
prompt: "Hello {{name}}! This is a test prompt.",
|
50
|
+
labels: ["test"],
|
51
|
+
config: { temperature: 0.7 }
|
52
|
+
)
|
53
|
+
|
54
|
+
puts "创建了 prompt: #{test_prompt.name}"
|
55
|
+
|
56
|
+
# 然后尝试获取它
|
57
|
+
retrieved_prompt = client.get_prompt("test-prompt")
|
58
|
+
puts "成功获取 prompt: #{retrieved_prompt.name}"
|
59
|
+
```
|
60
|
+
|
61
|
+
### 3. 检查 API 密钥
|
62
|
+
|
63
|
+
确认 API 密钥设置正确:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# 检查环境变量
|
67
|
+
puts "Public Key: #{ENV['LANGFUSE_PUBLIC_KEY']}"
|
68
|
+
puts "Secret Key: #{ENV['LANGFUSE_SECRET_KEY'] ? '已设置' : '未设置'}"
|
69
|
+
puts "Host: #{ENV['LANGFUSE_HOST'] || 'https://cloud.langfuse.com'}"
|
70
|
+
|
71
|
+
# 或者在代码中直接设置
|
72
|
+
client = Langfuse.new(
|
73
|
+
public_key: "your-public-key",
|
74
|
+
secret_key: "your-secret-key",
|
75
|
+
host: "https://cloud.langfuse.com"
|
76
|
+
)
|
77
|
+
```
|
78
|
+
|
79
|
+
### 4. 测试连接
|
80
|
+
|
81
|
+
测试与 Langfuse 服务器的基本连接:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
begin
|
85
|
+
response = client.send(:get, "/api/public/health")
|
86
|
+
puts "连接正常"
|
87
|
+
rescue => e
|
88
|
+
puts "连接失败: #{e.message}"
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
### 5. 启用调试模式
|
93
|
+
|
94
|
+
启用调试模式以获取更多信息:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
client = Langfuse.new(
|
98
|
+
public_key: "your-public-key",
|
99
|
+
secret_key: "your-secret-key",
|
100
|
+
host: "https://cloud.langfuse.com",
|
101
|
+
debug: true # 启用调试模式
|
102
|
+
)
|
103
|
+
```
|
104
|
+
|
105
|
+
## 改进的错误处理
|
106
|
+
|
107
|
+
Ruby SDK 已经改进了错误处理,现在会提供更清晰的错误信息:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
begin
|
111
|
+
prompt = client.get_prompt("non-existent-prompt")
|
112
|
+
rescue Langfuse::ValidationError => e
|
113
|
+
puts "验证错误: #{e.message}"
|
114
|
+
# 现在会显示:Resource not found (404). Server returned HTML page instead of JSON API response. This usually means the requested resource does not exist.
|
115
|
+
rescue Langfuse::AuthenticationError => e
|
116
|
+
puts "认证错误: #{e.message}"
|
117
|
+
rescue => e
|
118
|
+
puts "其他错误: #{e.message}"
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
## 常见问题
|
123
|
+
|
124
|
+
### Q: 为什么会收到 HTML 响应而不是 JSON?
|
125
|
+
|
126
|
+
A: 当 API 端点返回 404 错误时,Langfuse 服务器返回一个 HTML 错误页面而不是 JSON 响应。这是 Web 应用程序的常见行为。
|
127
|
+
|
128
|
+
### Q: 如何确认 prompt 名称是否正确?
|
129
|
+
|
130
|
+
A: 可以登录 Langfuse Web 界面查看所有可用的 prompt,或者使用 API 列出所有 prompt:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
# 注意:这需要使用底层 API 方法
|
134
|
+
# prompts = client.api.prompts.list()
|
135
|
+
```
|
136
|
+
|
137
|
+
### Q: 大小写是否重要?
|
138
|
+
|
139
|
+
A: 是的,prompt 名称是区分大小写的。确保使用正确的大小写。
|
140
|
+
|
141
|
+
### Q: 如何处理网络超时?
|
142
|
+
|
143
|
+
A: 可以调整超时设置:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
client = Langfuse.new(
|
147
|
+
public_key: "your-public-key",
|
148
|
+
secret_key: "your-secret-key",
|
149
|
+
host: "https://cloud.langfuse.com",
|
150
|
+
timeout: 60 # 60 秒超时
|
151
|
+
)
|
152
|
+
```
|
153
|
+
|
154
|
+
## 完整示例
|
155
|
+
|
156
|
+
以下是一个完整的示例,展示如何安全地获取 prompt:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
require 'langfuse'
|
160
|
+
|
161
|
+
# 初始化客户端
|
162
|
+
client = Langfuse.new(
|
163
|
+
public_key: ENV['LANGFUSE_PUBLIC_KEY'],
|
164
|
+
secret_key: ENV['LANGFUSE_SECRET_KEY'],
|
165
|
+
host: ENV['LANGFUSE_HOST'] || 'https://cloud.langfuse.com',
|
166
|
+
debug: true
|
167
|
+
)
|
168
|
+
|
169
|
+
# 安全地获取 prompt
|
170
|
+
def safe_get_prompt(client, name)
|
171
|
+
begin
|
172
|
+
prompt = client.get_prompt(name)
|
173
|
+
puts "✅ 成功获取 prompt: #{prompt.name}"
|
174
|
+
return prompt
|
175
|
+
rescue Langfuse::ValidationError => e
|
176
|
+
if e.message.include?("404")
|
177
|
+
puts "❌ Prompt '#{name}' 不存在"
|
178
|
+
puts "建议:请先在 Langfuse 中创建这个 prompt"
|
179
|
+
else
|
180
|
+
puts "❌ 验证错误: #{e.message}"
|
181
|
+
end
|
182
|
+
rescue Langfuse::AuthenticationError => e
|
183
|
+
puts "❌ 认证失败: #{e.message}"
|
184
|
+
puts "建议:检查 API 密钥是否正确"
|
185
|
+
rescue => e
|
186
|
+
puts "❌ 未知错误: #{e.message}"
|
187
|
+
end
|
188
|
+
return nil
|
189
|
+
end
|
190
|
+
|
191
|
+
# 使用示例
|
192
|
+
prompt = safe_get_prompt(client, "your-prompt-name")
|
193
|
+
if prompt
|
194
|
+
compiled = prompt.compile(variable: "value")
|
195
|
+
puts "编译后的 prompt: #{compiled}"
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
## 获取帮助
|
200
|
+
|
201
|
+
如果问题仍然存在,请:
|
202
|
+
|
203
|
+
1. 检查 [Langfuse 文档](https://langfuse.com/docs/prompts/get-started)
|
204
|
+
2. 访问 [GitHub Issues](https://github.com/langfuse/langfuse-ruby/issues)
|
205
|
+
3. 加入 [Discord 社区](https://discord.gg/langfuse)
|
206
|
+
4. 查看 [状态页面](https://status.langfuse.com) 了解服务状态
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Langfuse Ruby SDK
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/langfuse-ruby)
|
4
|
-
[](https://github.com/ai-firstly/langfuse-ruby/actions)
|
5
5
|
|
6
6
|
Ruby SDK for [Langfuse](https://langfuse.com) - the open-source LLM engineering platform. This SDK provides comprehensive tracing, prompt management, and evaluation capabilities for LLM applications.
|
7
7
|
|
@@ -422,7 +422,7 @@ For an interactive prompt that will allow you to experiment.
|
|
422
422
|
|
423
423
|
## Contributing
|
424
424
|
|
425
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
425
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ai-firstly/langfuse-ruby.
|
426
426
|
|
427
427
|
## License
|
428
428
|
|
@@ -433,4 +433,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
433
433
|
- [Langfuse Documentation](https://langfuse.com/docs)
|
434
434
|
- [Langfuse GitHub](https://github.com/langfuse/langfuse)
|
435
435
|
- [API Reference](https://api.reference.langfuse.com)
|
436
|
-
- [Ruby SDK Documentation](https://rubydoc.info/gems/langfuse-ruby)
|
436
|
+
- [Ruby SDK Documentation](https://rubydoc.info/gems/langfuse-ruby)
|
@@ -45,5 +45,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
45
45
|
- rubocop (~> 1.0)
|
46
46
|
- yard (~> 0.9)
|
47
47
|
|
48
|
-
[Unreleased]: https://github.com/
|
49
|
-
[0.1.0]: https://github.com/
|
48
|
+
[Unreleased]: https://github.com/ai-firstly/langfuse-ruby/compare/v0.1.0...HEAD
|
49
|
+
[0.1.0]: https://github.com/ai-firstly/langfuse-ruby/releases/tag/v0.1.0
|
@@ -30,10 +30,10 @@ git add .
|
|
30
30
|
git commit -m "Initial commit: Langfuse Ruby SDK v0.1.0"
|
31
31
|
|
32
32
|
# 添加远程仓库(替换为您的 GitHub 仓库)
|
33
|
-
git remote add origin https://github.com/
|
33
|
+
git remote add origin https://github.com/ai-firstly/langfuse-ruby.git
|
34
34
|
|
35
35
|
# 推送到 GitHub
|
36
|
-
git push -u origin
|
36
|
+
git push -u origin master
|
37
37
|
```
|
38
38
|
|
39
39
|
### 3. 创建 GitHub 仓库
|
@@ -50,7 +50,7 @@ git push -u origin main
|
|
50
50
|
|
51
51
|
```bash
|
52
52
|
# 构建 gem
|
53
|
-
gem build langfuse.gemspec
|
53
|
+
gem build langfuse-ruby.gemspec
|
54
54
|
|
55
55
|
# 检查构建结果
|
56
56
|
ls -la *.gem
|
@@ -60,13 +60,13 @@ ls -la *.gem
|
|
60
60
|
|
61
61
|
```bash
|
62
62
|
# 本地安装构建的 gem
|
63
|
-
gem install ./langfuse-0.1.0.gem
|
63
|
+
gem install ./langfuse-ruby-0.1.0.gem
|
64
64
|
|
65
65
|
# 测试安装是否成功
|
66
66
|
ruby -e "require 'langfuse'; puts 'Langfuse loaded successfully'"
|
67
67
|
|
68
68
|
# 卸载本地测试版本
|
69
|
-
gem uninstall langfuse
|
69
|
+
gem uninstall langfuse-ruby
|
70
70
|
```
|
71
71
|
|
72
72
|
### 3. 运行完整测试
|
@@ -111,7 +111,7 @@ chmod 0600 ~/.gem/credentials
|
|
111
111
|
gem build langfuse.gemspec
|
112
112
|
|
113
113
|
# 发布到 RubyGems
|
114
|
-
gem push langfuse-0.1.0.gem
|
114
|
+
gem push langfuse-ruby-0.1.0.gem
|
115
115
|
```
|
116
116
|
|
117
117
|
## 📊 发布后验证
|
data/docs/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Langfuse Ruby SDK 文档
|
2
|
+
|
3
|
+
本目录包含 Langfuse Ruby SDK 的所有文档。
|
4
|
+
|
5
|
+
## 📚 文档索引
|
6
|
+
|
7
|
+
### 开发和发布
|
8
|
+
- [📋 发布指南](PUBLISH_GUIDE.md) - 详细的 gem 发布流程
|
9
|
+
- [✅ 发布检查清单](RELEASE_CHECKLIST.md) - 发布前的检查项目
|
10
|
+
- [📝 变更日志](CHANGELOG.md) - 版本更新记录
|
11
|
+
|
12
|
+
### 项目概览
|
13
|
+
- [📊 项目总结](PROJECT_SUMMARY.md) - 项目整体介绍
|
14
|
+
- [🎯 最终总结](FINAL_SUMMARY.md) - 项目完成情况总结
|
15
|
+
|
16
|
+
## 🔗 相关链接
|
17
|
+
|
18
|
+
- [主要 README](../README.md) - 项目主页和使用说明
|
19
|
+
- [示例代码](../examples/) - 使用示例
|
20
|
+
- [API 文档](../lib/) - 源代码文档
|
21
|
+
- [测试文件](../spec/) - 测试用例
|
22
|
+
|
23
|
+
## 📞 获取帮助
|
24
|
+
|
25
|
+
如果您在使用过程中遇到问题,请:
|
26
|
+
|
27
|
+
1. 查看相关文档
|
28
|
+
2. 检查 [GitHub Issues](https://github.com/ai-firstly/langfuse-ruby/issues)
|
29
|
+
3. 提交新的 Issue 或 Pull Request
|
30
|
+
|
31
|
+
---
|
32
|
+
|
33
|
+
**感谢您使用 Langfuse Ruby SDK!** 🚀
|
data/langfuse-ruby.gemspec
CHANGED
@@ -1,20 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'lib/langfuse/version'
|
2
4
|
|
3
5
|
Gem::Specification.new do |spec|
|
4
6
|
spec.name = 'langfuse-ruby'
|
5
7
|
spec.version = Langfuse::VERSION
|
6
|
-
spec.authors = ['
|
7
|
-
spec.email = ['
|
8
|
+
spec.authors = ['Richard Sun']
|
9
|
+
spec.email = ['richard.sun@ai-firstly.com']
|
8
10
|
spec.summary = 'Ruby SDK for Langfuse - Open source LLM engineering platform'
|
9
|
-
spec.description = 'Ruby client library for Langfuse, providing tracing, prompt management,
|
10
|
-
|
11
|
+
spec.description = 'Ruby client library for Langfuse, providing tracing, prompt management, ' \
|
12
|
+
'and evaluation capabilities for LLM applications'
|
13
|
+
spec.homepage = 'https://langfuse.com'
|
11
14
|
spec.license = 'MIT'
|
12
15
|
spec.required_ruby_version = '>= 2.7.0'
|
13
16
|
|
14
17
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
15
|
-
spec.metadata['homepage_uri'] =
|
16
|
-
spec.metadata['source_code_uri'] = 'https://github.com/
|
17
|
-
spec.metadata['changelog_uri'] = 'https://github.com/
|
18
|
+
spec.metadata['homepage_uri'] = 'https://langfuse.com/docs/sdk/ruby'
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/ai-firstly/langfuse-ruby'
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/ai-firstly/langfuse-ruby/blob/main/CHANGELOG.md'
|
21
|
+
spec.metadata['documentation_uri'] = 'https://rubydoc.info/gems/langfuse-ruby'
|
22
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/ai-firstly/langfuse-ruby/issues'
|
18
23
|
|
19
24
|
# Specify which files should be added to the gem when it is released.
|
20
25
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
data/lib/langfuse/client.rb
CHANGED
@@ -16,8 +16,8 @@ module Langfuse
|
|
16
16
|
@timeout = timeout || Langfuse.configuration.timeout
|
17
17
|
@retries = retries || Langfuse.configuration.retries
|
18
18
|
|
19
|
-
raise AuthenticationError,
|
20
|
-
raise AuthenticationError,
|
19
|
+
raise AuthenticationError, 'Public key is required' unless @public_key
|
20
|
+
raise AuthenticationError, 'Secret key is required' unless @secret_key
|
21
21
|
|
22
22
|
@connection = build_connection
|
23
23
|
@event_queue = Concurrent::Array.new
|
@@ -95,8 +95,8 @@ module Langfuse
|
|
95
95
|
def get_prompt(name, version: nil, label: nil, cache_ttl_seconds: 60)
|
96
96
|
cache_key = "prompt:#{name}:#{version}:#{label}"
|
97
97
|
|
98
|
-
if cached_prompt = @prompt_cache&.dig(cache_key)
|
99
|
-
return cached_prompt[:prompt]
|
98
|
+
if (cached_prompt = @prompt_cache&.dig(cache_key)) && (Time.now - cached_prompt[:cached_at] < cache_ttl_seconds)
|
99
|
+
return cached_prompt[:prompt]
|
100
100
|
end
|
101
101
|
|
102
102
|
path = "/api/public/prompts/#{name}"
|
@@ -104,7 +104,22 @@ module Langfuse
|
|
104
104
|
params[:version] = version if version
|
105
105
|
params[:label] = label if label
|
106
106
|
|
107
|
+
puts "Making request to: #{@host}#{path} with params: #{params}" if @debug
|
108
|
+
|
107
109
|
response = get(path, params)
|
110
|
+
|
111
|
+
puts "Response status: #{response.status}" if @debug
|
112
|
+
puts "Response headers: #{response.headers}" if @debug
|
113
|
+
puts "Response body type: #{response.body.class}" if @debug
|
114
|
+
|
115
|
+
# Check if response body is a string (HTML) instead of parsed JSON
|
116
|
+
if response.body.is_a?(String) && response.body.include?('<!DOCTYPE html>')
|
117
|
+
puts 'Received HTML response instead of JSON:' if @debug
|
118
|
+
puts response.body[0..200] if @debug
|
119
|
+
raise APIError,
|
120
|
+
'Received HTML response instead of JSON. This usually indicates a 404 error or incorrect API endpoint.'
|
121
|
+
end
|
122
|
+
|
108
123
|
prompt = Prompt.new(response.body)
|
109
124
|
|
110
125
|
# Cache the prompt
|
@@ -123,12 +138,12 @@ module Langfuse
|
|
123
138
|
**kwargs
|
124
139
|
}
|
125
140
|
|
126
|
-
response = post(
|
141
|
+
response = post('/api/public/prompts', data)
|
127
142
|
Prompt.new(response.body)
|
128
143
|
end
|
129
144
|
|
130
145
|
# Score/Evaluation operations
|
131
|
-
def score(trace_id: nil, observation_id: nil,
|
146
|
+
def score(name:, value:, trace_id: nil, observation_id: nil, data_type: nil, comment: nil, **kwargs)
|
132
147
|
data = {
|
133
148
|
name: name,
|
134
149
|
value: value,
|
@@ -187,15 +202,15 @@ module Langfuse
|
|
187
202
|
batch: events,
|
188
203
|
metadata: {
|
189
204
|
batch_size: events.length,
|
190
|
-
sdk_name:
|
205
|
+
sdk_name: 'langfuse-ruby',
|
191
206
|
sdk_version: Langfuse::VERSION
|
192
207
|
}
|
193
208
|
}
|
194
209
|
|
195
210
|
begin
|
196
|
-
response = post(
|
211
|
+
response = post('/api/public/ingestion', batch_data)
|
197
212
|
puts "Flushed #{events.length} events" if @debug
|
198
|
-
rescue => e
|
213
|
+
rescue StandardError => e
|
199
214
|
puts "Failed to flush events: #{e.message}" if @debug
|
200
215
|
# Re-queue events on failure
|
201
216
|
events.each { |event| @event_queue << event }
|
@@ -214,9 +229,13 @@ module Langfuse
|
|
214
229
|
Faraday.new(url: @host) do |conn|
|
215
230
|
conn.request :authorization, :basic, @public_key, @secret_key
|
216
231
|
conn.request :json
|
232
|
+
# 更宽松的 JSON 响应处理,支持更多 content-type
|
217
233
|
conn.response :json, content_type: /\bjson$/
|
218
234
|
conn.adapter Faraday.default_adapter
|
219
235
|
conn.options.timeout = @timeout
|
236
|
+
|
237
|
+
# 添加响应中间件来处理错误响应
|
238
|
+
conn.response :logger if @debug
|
220
239
|
end
|
221
240
|
end
|
222
241
|
|
@@ -236,29 +255,40 @@ module Langfuse
|
|
236
255
|
rescue Faraday::ConnectionFailed => e
|
237
256
|
if retries_left > 0
|
238
257
|
retries_left -= 1
|
239
|
-
sleep(2
|
258
|
+
sleep(2**(@retries - retries_left))
|
240
259
|
retry
|
241
260
|
end
|
242
261
|
raise NetworkError, "Connection failed: #{e.message}"
|
243
|
-
rescue => e
|
262
|
+
rescue StandardError => e
|
244
263
|
raise APIError, "Request failed: #{e.message}"
|
245
264
|
end
|
246
265
|
end
|
247
266
|
|
248
267
|
def handle_response(response)
|
268
|
+
puts "Handling response with status: #{response.status}" if @debug
|
269
|
+
|
249
270
|
case response.status
|
250
271
|
when 200..299
|
251
272
|
response
|
252
273
|
when 401
|
253
274
|
raise AuthenticationError, "Authentication failed: #{response.body}"
|
275
|
+
when 404
|
276
|
+
# 404 错误通常返回 HTML 页面
|
277
|
+
error_message = 'Resource not found (404)'
|
278
|
+
if response.body.is_a?(String) && response.body.include?('<!DOCTYPE html>')
|
279
|
+
error_message += '. Server returned HTML page instead of JSON API response. This usually means the requested resource does not exist.'
|
280
|
+
else
|
281
|
+
error_message += ": #{response.body}"
|
282
|
+
end
|
283
|
+
raise ValidationError, error_message
|
254
284
|
when 429
|
255
285
|
raise RateLimitError, "Rate limit exceeded: #{response.body}"
|
256
286
|
when 400..499
|
257
|
-
raise ValidationError, "Client error: #{response.body}"
|
287
|
+
raise ValidationError, "Client error (#{response.status}): #{response.body}"
|
258
288
|
when 500..599
|
259
|
-
raise APIError, "Server error: #{response.body}"
|
289
|
+
raise APIError, "Server error (#{response.status}): #{response.body}"
|
260
290
|
else
|
261
|
-
raise APIError, "Unexpected response
|
291
|
+
raise APIError, "Unexpected response (#{response.status}): #{response.body}"
|
262
292
|
end
|
263
293
|
end
|
264
294
|
|
@@ -268,7 +298,7 @@ module Langfuse
|
|
268
298
|
sleep(5) # Flush every 5 seconds
|
269
299
|
begin
|
270
300
|
flush unless @event_queue.empty?
|
271
|
-
rescue => e
|
301
|
+
rescue StandardError => e
|
272
302
|
puts "Error in flush thread: #{e.message}" if @debug
|
273
303
|
end
|
274
304
|
end
|
data/lib/langfuse/evaluation.rb
CHANGED
@@ -67,7 +67,7 @@ module Langfuse
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def evaluate(input, output, expected: nil, context: nil)
|
70
|
-
raise NotImplementedError,
|
70
|
+
raise NotImplementedError, 'Subclasses must implement evaluate method'
|
71
71
|
end
|
72
72
|
|
73
73
|
protected
|
@@ -129,7 +129,7 @@ module Langfuse
|
|
129
129
|
length = output.to_s.length
|
130
130
|
|
131
131
|
if @min_length && @max_length
|
132
|
-
score =
|
132
|
+
score = length >= @min_length && length <= @max_length ? 1 : 0
|
133
133
|
comment = score == 1 ? "Length #{length} within range" : "Length #{length} outside range #{@min_length}-#{@max_length}"
|
134
134
|
elsif @min_length
|
135
135
|
score = length >= @min_length ? 1 : 0
|
@@ -151,7 +151,7 @@ module Langfuse
|
|
151
151
|
end
|
152
152
|
|
153
153
|
class RegexEvaluator < BaseEvaluator
|
154
|
-
def initialize(name: 'regex', description: 'Regex evaluator'
|
154
|
+
def initialize(pattern:, name: 'regex', description: 'Regex evaluator')
|
155
155
|
super(name: name, description: description)
|
156
156
|
@pattern = pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern)
|
157
157
|
end
|
@@ -205,11 +205,11 @@ module Langfuse
|
|
205
205
|
|
206
206
|
(1..str1.length).each do |i|
|
207
207
|
(1..str2.length).each do |j|
|
208
|
-
cost = str1[i-1] == str2[j-1] ? 0 : 1
|
208
|
+
cost = str1[i - 1] == str2[j - 1] ? 0 : 1
|
209
209
|
matrix[i][j] = [
|
210
|
-
matrix[i-1][j] + 1, # deletion
|
211
|
-
matrix[i][j-1] + 1, # insertion
|
212
|
-
matrix[i-1][j-1] + cost # substitution
|
210
|
+
matrix[i - 1][j] + 1, # deletion
|
211
|
+
matrix[i][j - 1] + 1, # insertion
|
212
|
+
matrix[i - 1][j - 1] + cost # substitution
|
213
213
|
].min
|
214
214
|
end
|
215
215
|
end
|
@@ -219,7 +219,8 @@ module Langfuse
|
|
219
219
|
end
|
220
220
|
|
221
221
|
class LLMEvaluator < BaseEvaluator
|
222
|
-
def initialize(name: 'llm_evaluator', description: 'LLM-based evaluator',
|
222
|
+
def initialize(client:, name: 'llm_evaluator', description: 'LLM-based evaluator', model: 'gpt-3.5-turbo',
|
223
|
+
prompt_template: nil)
|
223
224
|
super(name: name, description: description)
|
224
225
|
@client = client
|
225
226
|
@model = model
|
data/lib/langfuse/prompt.rb
CHANGED
@@ -61,7 +61,7 @@ module Langfuse
|
|
61
61
|
def text_to_langchain_prompt
|
62
62
|
# Convert text prompt to LangChain PromptTemplate format
|
63
63
|
{
|
64
|
-
_type:
|
64
|
+
_type: 'prompt',
|
65
65
|
input_variables: extract_variables(@prompt),
|
66
66
|
template: @prompt
|
67
67
|
}
|
@@ -78,7 +78,7 @@ module Langfuse
|
|
78
78
|
end
|
79
79
|
|
80
80
|
{
|
81
|
-
_type:
|
81
|
+
_type: 'chat',
|
82
82
|
messages: messages,
|
83
83
|
input_variables: messages.flat_map { |m| m[:input_variables] }.uniq
|
84
84
|
}
|
data/lib/langfuse/version.rb
CHANGED
data/lib/langfuse.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
|
-
|
2
|
-
require_relative "langfuse/client"
|
3
|
-
require_relative "langfuse/trace"
|
4
|
-
require_relative "langfuse/span"
|
5
|
-
require_relative "langfuse/generation"
|
6
|
-
require_relative "langfuse/prompt"
|
7
|
-
require_relative "langfuse/evaluation"
|
8
|
-
require_relative "langfuse/errors"
|
9
|
-
require_relative "langfuse/utils"
|
1
|
+
# frozen_string_literal: true
|
10
2
|
|
3
|
+
require_relative 'langfuse/version'
|
4
|
+
require_relative 'langfuse/client'
|
5
|
+
require_relative 'langfuse/trace'
|
6
|
+
require_relative 'langfuse/span'
|
7
|
+
require_relative 'langfuse/generation'
|
8
|
+
require_relative 'langfuse/prompt'
|
9
|
+
require_relative 'langfuse/evaluation'
|
10
|
+
require_relative 'langfuse/errors'
|
11
|
+
require_relative 'langfuse/utils'
|
12
|
+
|
13
|
+
# Ruby SDK for Langfuse - Open source LLM engineering platform
|
11
14
|
module Langfuse
|
12
15
|
class << self
|
13
16
|
# Configure the Langfuse client with default settings
|
@@ -25,13 +28,14 @@ module Langfuse
|
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
31
|
+
# Configuration class for Langfuse client settings
|
28
32
|
class Configuration
|
29
33
|
attr_accessor :public_key, :secret_key, :host, :debug, :timeout, :retries
|
30
34
|
|
31
35
|
def initialize
|
32
36
|
@public_key = nil
|
33
37
|
@secret_key = nil
|
34
|
-
@host =
|
38
|
+
@host = 'https://cloud.langfuse.com'
|
35
39
|
@debug = false
|
36
40
|
@timeout = 30
|
37
41
|
@retries = 3
|
data/scripts/release.sh
CHANGED
@@ -116,5 +116,5 @@ echo " 3. Announce the release"
|
|
116
116
|
echo
|
117
117
|
echo "🔗 Useful links:"
|
118
118
|
echo " - RubyGems: https://rubygems.org/gems/langfuse"
|
119
|
-
echo " - GitHub: https://github.com/
|
120
|
-
echo " - Documentation: https://github.com/
|
119
|
+
echo " - GitHub: https://github.com/ai-firstly/langfuse-ruby"
|
120
|
+
echo " - Documentation: https://github.com/ai-firstly/langfuse-ruby#readme"
|
data/scripts/verify_release.rb
CHANGED
@@ -135,5 +135,5 @@ end
|
|
135
135
|
|
136
136
|
puts "\n🔗 Useful links:"
|
137
137
|
puts ' - RubyGems page: https://rubygems.org/gems/langfuse'
|
138
|
-
puts ' - Documentation: https://github.com/
|
139
|
-
puts ' - Issues: https://github.com/
|
138
|
+
puts ' - Documentation: https://github.com/ai-firstly/langfuse-ruby'
|
139
|
+
puts ' - Issues: https://github.com/ai-firstly/langfuse-ruby/issues'
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: langfuse-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Richard Sun
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
@@ -167,7 +167,7 @@ dependencies:
|
|
167
167
|
description: Ruby client library for Langfuse, providing tracing, prompt management,
|
168
168
|
and evaluation capabilities for LLM applications
|
169
169
|
email:
|
170
|
-
-
|
170
|
+
- richard.sun@ai-firstly.com
|
171
171
|
executables: []
|
172
172
|
extensions: []
|
173
173
|
extra_rdoc_files: []
|
@@ -175,16 +175,18 @@ files:
|
|
175
175
|
- ".github/workflows/ci.yml"
|
176
176
|
- ".github/workflows/release.yml"
|
177
177
|
- ".gitignore"
|
178
|
-
- CHANGELOG.md
|
179
|
-
- FINAL_SUMMARY.md
|
180
178
|
- Gemfile
|
181
179
|
- Gemfile.lock
|
182
180
|
- LICENSE
|
183
|
-
-
|
184
|
-
- PUBLISH_GUIDE.md
|
181
|
+
- PROMPT_TROUBLESHOOTING.md
|
185
182
|
- README.md
|
186
|
-
- RELEASE_CHECKLIST.md
|
187
183
|
- Rakefile
|
184
|
+
- docs/CHANGELOG.md
|
185
|
+
- docs/FINAL_SUMMARY.md
|
186
|
+
- docs/PROJECT_SUMMARY.md
|
187
|
+
- docs/PUBLISH_GUIDE.md
|
188
|
+
- docs/README.md
|
189
|
+
- docs/RELEASE_CHECKLIST.md
|
188
190
|
- examples/basic_tracing.rb
|
189
191
|
- examples/prompt_management.rb
|
190
192
|
- langfuse-ruby.gemspec
|
@@ -202,14 +204,16 @@ files:
|
|
202
204
|
- scripts/verify_release.rb
|
203
205
|
- test_basic.rb
|
204
206
|
- test_offline.rb
|
205
|
-
homepage: https://
|
207
|
+
homepage: https://langfuse.com
|
206
208
|
licenses:
|
207
209
|
- MIT
|
208
210
|
metadata:
|
209
211
|
allowed_push_host: https://rubygems.org
|
210
|
-
homepage_uri: https://
|
211
|
-
source_code_uri: https://github.com/
|
212
|
-
changelog_uri: https://github.com/
|
212
|
+
homepage_uri: https://langfuse.com/docs/sdk/ruby
|
213
|
+
source_code_uri: https://github.com/ai-firstly/langfuse-ruby
|
214
|
+
changelog_uri: https://github.com/ai-firstly/langfuse-ruby/blob/main/CHANGELOG.md
|
215
|
+
documentation_uri: https://rubydoc.info/gems/langfuse-ruby
|
216
|
+
bug_tracker_uri: https://github.com/ai-firstly/langfuse-ruby/issues
|
213
217
|
post_install_message:
|
214
218
|
rdoc_options: []
|
215
219
|
require_paths:
|
File without changes
|
File without changes
|
File without changes
|