langfuse-ruby 0.1.1 → 0.1.2
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/CHANGELOG.md +44 -0
- data/Gemfile +5 -5
- data/Gemfile.lock +1 -1
- data/docs/PUBLISH_GUIDE.md +2 -2
- data/docs/README.md +0 -4
- data/examples/connection_config_demo.rb +127 -0
- data/examples/prompt_management.rb +62 -71
- data/lib/langfuse/client.rb +15 -6
- data/lib/langfuse/version.rb +1 -1
- data/lib/langfuse.rb +1 -1
- metadata +3 -5
- data/PROMPT_TROUBLESHOOTING.md +0 -206
- data/docs/CHANGELOG.md +0 -49
- data/docs/PROJECT_SUMMARY.md +0 -263
- data/test_basic.rb +0 -183
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bb8cc1f797c0b240830c5f909665dde61bb8a5540f1db8a04393ae0d741ee44
|
4
|
+
data.tar.gz: bc5b9e1dc24e2861ac66955bec4dccd25bbadaf1a3c5f59ddbacd784a50b2180
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5486239447652d3b97eb6200bc2f24ee829bef24da86409747f6a250fcc1126ce68841673b0e67da56a75e08ff4ec1bc9edf4b241c3431b855abdf2befdd7b9
|
7
|
+
data.tar.gz: 88b61075d0a394629dec59bbec509a7f4c80b0269a887dcef866b3a8a250fd75b362fe84fc6247e72b5305935702a7175c1db825461bb05270145912d6e8f79e
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [0.1.1] - 2025-01-12
|
9
|
+
|
10
|
+
### Fixed
|
11
|
+
- Improved error handling for `get_prompt` method when prompt doesn't exist
|
12
|
+
- Better error messages for 404 responses that return HTML instead of JSON
|
13
|
+
- Enhanced debugging capabilities with detailed request/response logging
|
14
|
+
|
15
|
+
### Added
|
16
|
+
- Comprehensive troubleshooting guide for prompt management issues
|
17
|
+
- Better detection of HTML responses vs JSON responses
|
18
|
+
- More specific error types for different failure scenarios
|
19
|
+
|
20
|
+
### Changed
|
21
|
+
- Updated gemspec metadata to avoid RubyGems warnings
|
22
|
+
- Improved documentation with clearer error handling examples
|
23
|
+
|
24
|
+
## [0.1.0] - 2025-01-12
|
25
|
+
|
26
|
+
### Added
|
27
|
+
- Initial release of Langfuse Ruby SDK
|
28
|
+
- Complete tracing capabilities with traces, spans, and generations
|
29
|
+
- Prompt management with versioning and caching
|
30
|
+
- Built-in evaluators (exact match, similarity, length, contains, regex)
|
31
|
+
- Custom scoring and evaluation pipeline support
|
32
|
+
- Async event processing with automatic batching
|
33
|
+
- Comprehensive error handling and validation
|
34
|
+
- Framework integration examples (Rails, Sidekiq)
|
35
|
+
- Full test suite with RSpec
|
36
|
+
- Documentation and examples
|
37
|
+
|
38
|
+
### Features
|
39
|
+
- **Tracing**: Full observability for LLM applications
|
40
|
+
- **Prompt Management**: Version control and deployment of prompts
|
41
|
+
- **Evaluation**: Multiple built-in evaluators and custom scoring
|
42
|
+
- **Async Processing**: Background event processing with batching
|
43
|
+
- **Type Safety**: Comprehensive error handling
|
44
|
+
- **Integration**: Easy integration with Ruby frameworks
|
data/Gemfile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in langfuse.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem
|
7
|
-
gem
|
8
|
-
gem
|
9
|
-
gem
|
6
|
+
gem 'rake', '~> 13.0'
|
7
|
+
gem 'rspec', '~> 3.0'
|
8
|
+
gem 'rubocop', '~> 1.21'
|
9
|
+
gem 'yard', '~> 0.9'
|
data/Gemfile.lock
CHANGED
data/docs/PUBLISH_GUIDE.md
CHANGED
@@ -108,10 +108,10 @@ chmod 0600 ~/.gem/credentials
|
|
108
108
|
|
109
109
|
```bash
|
110
110
|
# 构建最新版本
|
111
|
-
gem build langfuse.gemspec
|
111
|
+
gem build langfuse-ruby.gemspec
|
112
112
|
|
113
113
|
# 发布到 RubyGems
|
114
|
-
gem push langfuse-ruby-0.1.
|
114
|
+
gem push langfuse-ruby-0.1.x.gem
|
115
115
|
```
|
116
116
|
|
117
117
|
## 📊 发布后验证
|
data/docs/README.md
CHANGED
@@ -0,0 +1,127 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/langfuse'
|
4
|
+
|
5
|
+
puts '🚀 Langfuse Ruby SDK 连接配置演示'
|
6
|
+
puts '=' * 50
|
7
|
+
|
8
|
+
# 显示默认配置
|
9
|
+
puts "\n📋 默认配置信息:"
|
10
|
+
puts " 默认主机: #{Langfuse.configuration.host}"
|
11
|
+
puts " 默认超时: #{Langfuse.configuration.timeout}秒"
|
12
|
+
puts " 默认重试: #{Langfuse.configuration.retries}次"
|
13
|
+
|
14
|
+
# 方法 1: 使用测试密钥创建客户端(仅用于演示)
|
15
|
+
puts "\n📝 方法 1: 直接参数配置"
|
16
|
+
puts '代码示例:'
|
17
|
+
puts 'client = Langfuse.new('
|
18
|
+
puts " public_key: 'pk-lf-your-public-key',"
|
19
|
+
puts " secret_key: 'sk-lf-your-secret-key',"
|
20
|
+
puts " host: 'https://us.cloud.langfuse.com'"
|
21
|
+
puts ')'
|
22
|
+
|
23
|
+
# 使用测试密钥创建客户端
|
24
|
+
test_client = Langfuse.new(
|
25
|
+
public_key: 'test-public-key',
|
26
|
+
secret_key: 'test-secret-key',
|
27
|
+
host: 'https://us.cloud.langfuse.com'
|
28
|
+
)
|
29
|
+
|
30
|
+
puts '✅ 客户端配置成功'
|
31
|
+
puts " 主机: #{test_client.host}"
|
32
|
+
puts " 超时: #{test_client.timeout}秒"
|
33
|
+
puts " 重试: #{test_client.retries}次"
|
34
|
+
|
35
|
+
# 方法 2: 全局配置
|
36
|
+
puts "\n📝 方法 2: 全局配置"
|
37
|
+
puts '代码示例:'
|
38
|
+
puts 'Langfuse.configure do |config|'
|
39
|
+
puts " config.public_key = 'pk-lf-your-public-key'"
|
40
|
+
puts " config.secret_key = 'sk-lf-your-secret-key'"
|
41
|
+
puts " config.host = 'https://us.cloud.langfuse.com'"
|
42
|
+
puts ' config.debug = true'
|
43
|
+
puts 'end'
|
44
|
+
|
45
|
+
Langfuse.configure do |config|
|
46
|
+
config.public_key = 'test-public-key'
|
47
|
+
config.secret_key = 'test-secret-key'
|
48
|
+
config.host = 'https://us.cloud.langfuse.com'
|
49
|
+
config.debug = true
|
50
|
+
config.timeout = 60
|
51
|
+
config.retries = 5
|
52
|
+
end
|
53
|
+
|
54
|
+
global_client = Langfuse.new
|
55
|
+
puts '✅ 全局配置成功'
|
56
|
+
puts " 主机: #{global_client.host}"
|
57
|
+
puts " 调试模式: #{global_client.debug}"
|
58
|
+
puts " 超时: #{global_client.timeout}秒"
|
59
|
+
puts " 重试: #{global_client.retries}次"
|
60
|
+
|
61
|
+
# 方法 3: 环境变量配置
|
62
|
+
puts "\n📝 方法 3: 环境变量配置"
|
63
|
+
puts '设置环境变量:'
|
64
|
+
puts "export LANGFUSE_PUBLIC_KEY='pk-lf-your-public-key'"
|
65
|
+
puts "export LANGFUSE_SECRET_KEY='sk-lf-your-secret-key'"
|
66
|
+
puts "export LANGFUSE_HOST='https://us.cloud.langfuse.com'"
|
67
|
+
puts ''
|
68
|
+
puts '然后使用:'
|
69
|
+
puts 'client = Langfuse.new'
|
70
|
+
|
71
|
+
if ENV['LANGFUSE_PUBLIC_KEY'] && ENV['LANGFUSE_SECRET_KEY']
|
72
|
+
env_client = Langfuse.new
|
73
|
+
puts '✅ 环境变量配置成功'
|
74
|
+
puts " 主机: #{env_client.host}"
|
75
|
+
else
|
76
|
+
puts '⚠️ 环境变量未设置,跳过此示例'
|
77
|
+
end
|
78
|
+
|
79
|
+
# 连接配置详情
|
80
|
+
puts "\n🔧 连接配置详情:"
|
81
|
+
puts '根据 Langfuse 官方文档:'
|
82
|
+
puts '1. 认证方式: HTTP Basic Auth'
|
83
|
+
puts '2. 用户名: Langfuse Public Key (pk-lf-...)'
|
84
|
+
puts '3. 密码: Langfuse Secret Key (sk-lf-...)'
|
85
|
+
puts '4. 默认服务器: https://us.cloud.langfuse.com'
|
86
|
+
puts '5. 内容类型: application/json'
|
87
|
+
puts "6. User-Agent: langfuse-ruby/#{Langfuse::VERSION}"
|
88
|
+
|
89
|
+
# 创建测试 trace(不发送到服务器)
|
90
|
+
puts "\n🧪 创建测试 Trace(离线):"
|
91
|
+
begin
|
92
|
+
trace = test_client.trace(
|
93
|
+
name: 'connection-test',
|
94
|
+
user_id: 'demo-user',
|
95
|
+
input: { message: '测试连接配置' },
|
96
|
+
metadata: { demo: true }
|
97
|
+
)
|
98
|
+
|
99
|
+
puts '✅ Trace 创建成功'
|
100
|
+
puts " ID: #{trace.id}"
|
101
|
+
puts " 名称: #{trace.name}"
|
102
|
+
puts " 用户ID: #{trace.user_id}"
|
103
|
+
|
104
|
+
# 添加 generation
|
105
|
+
generation = trace.generation(
|
106
|
+
name: 'demo-generation',
|
107
|
+
model: 'gpt-3.5-turbo',
|
108
|
+
input: [{ role: 'user', content: 'Hello!' }],
|
109
|
+
output: { content: '你好!' },
|
110
|
+
usage: { prompt_tokens: 5, completion_tokens: 3, total_tokens: 8 }
|
111
|
+
)
|
112
|
+
|
113
|
+
puts '✅ Generation 创建成功'
|
114
|
+
puts " ID: #{generation.id}"
|
115
|
+
puts " 模型: #{generation.model}"
|
116
|
+
rescue StandardError => e
|
117
|
+
puts "❌ 测试失败: #{e.message}"
|
118
|
+
end
|
119
|
+
|
120
|
+
puts "\n📚 使用提示:"
|
121
|
+
puts "1. 替换示例中的 'test-public-key' 和 'test-secret-key' 为您的真实 API 密钥"
|
122
|
+
puts '2. 确保网络连接正常'
|
123
|
+
puts '3. 启用 debug 模式可以查看详细的请求日志'
|
124
|
+
puts '4. 调用 client.flush 来发送事件到服务器'
|
125
|
+
puts '5. 使用 client.shutdown 来优雅地关闭客户端'
|
126
|
+
|
127
|
+
puts "\n🎉 连接配置演示完成!"
|
@@ -9,7 +9,7 @@ client = Langfuse.new(
|
|
9
9
|
host: ENV['LANGFUSE_HOST'] || 'https://cloud.langfuse.com'
|
10
10
|
)
|
11
11
|
|
12
|
-
puts
|
12
|
+
puts '🚀 Starting prompt management example...'
|
13
13
|
|
14
14
|
# Example 1: Create and use text prompts
|
15
15
|
puts "\n📝 Example 1: Create and use text prompts"
|
@@ -17,9 +17,9 @@ puts "\n📝 Example 1: Create and use text prompts"
|
|
17
17
|
begin
|
18
18
|
# Create a text prompt
|
19
19
|
text_prompt = client.create_prompt(
|
20
|
-
name:
|
21
|
-
prompt:
|
22
|
-
labels: [
|
20
|
+
name: 'greeting-prompt',
|
21
|
+
prompt: 'Hello {{user_name}}! Welcome to {{service_name}}. How can I help you with {{topic}} today?',
|
22
|
+
labels: %w[greeting customer-service],
|
23
23
|
config: {
|
24
24
|
temperature: 0.7,
|
25
25
|
max_tokens: 100
|
@@ -27,24 +27,22 @@ begin
|
|
27
27
|
)
|
28
28
|
|
29
29
|
puts "Created text prompt: #{text_prompt.name} (Version: #{text_prompt.version})"
|
30
|
-
|
31
30
|
rescue Langfuse::APIError => e
|
32
31
|
puts "Note: Prompt might already exist - #{e.message}"
|
33
32
|
end
|
34
33
|
|
35
34
|
# Get and use the prompt
|
36
35
|
begin
|
37
|
-
prompt = client.get_prompt(
|
36
|
+
prompt = client.get_prompt('greeting-prompt')
|
38
37
|
|
39
38
|
# Compile prompt with variables
|
40
39
|
compiled_text = prompt.compile(
|
41
|
-
user_name:
|
42
|
-
service_name:
|
43
|
-
topic:
|
40
|
+
user_name: 'Alice',
|
41
|
+
service_name: 'AI Assistant',
|
42
|
+
topic: 'machine learning'
|
44
43
|
)
|
45
44
|
|
46
45
|
puts "Compiled prompt: #{compiled_text}"
|
47
|
-
|
48
46
|
rescue Langfuse::APIError => e
|
49
47
|
puts "Could not retrieve prompt: #{e.message}"
|
50
48
|
end
|
@@ -55,18 +53,18 @@ puts "\n💬 Example 2: Create and use chat prompts"
|
|
55
53
|
begin
|
56
54
|
# Create a chat prompt
|
57
55
|
chat_prompt = client.create_prompt(
|
58
|
-
name:
|
56
|
+
name: 'ai-assistant-chat',
|
59
57
|
prompt: [
|
60
58
|
{
|
61
|
-
role:
|
62
|
-
content:
|
59
|
+
role: 'system',
|
60
|
+
content: 'You are a helpful AI assistant specialized in {{domain}}. Always be {{tone}} and provide {{detail_level}} answers.'
|
63
61
|
},
|
64
62
|
{
|
65
|
-
role:
|
66
|
-
content:
|
63
|
+
role: 'user',
|
64
|
+
content: '{{user_message}}'
|
67
65
|
}
|
68
66
|
],
|
69
|
-
labels: [
|
67
|
+
labels: %w[chat assistant ai],
|
70
68
|
config: {
|
71
69
|
temperature: 0.8,
|
72
70
|
max_tokens: 200
|
@@ -74,28 +72,26 @@ begin
|
|
74
72
|
)
|
75
73
|
|
76
74
|
puts "Created chat prompt: #{chat_prompt.name}"
|
77
|
-
|
78
75
|
rescue Langfuse::APIError => e
|
79
76
|
puts "Note: Chat prompt might already exist - #{e.message}"
|
80
77
|
end
|
81
78
|
|
82
79
|
# Get and use the chat prompt
|
83
80
|
begin
|
84
|
-
chat_prompt = client.get_prompt(
|
81
|
+
chat_prompt = client.get_prompt('ai-assistant-chat')
|
85
82
|
|
86
83
|
# Compile chat prompt with variables
|
87
84
|
compiled_messages = chat_prompt.compile(
|
88
|
-
domain:
|
89
|
-
tone:
|
90
|
-
detail_level:
|
91
|
-
user_message:
|
85
|
+
domain: 'software development',
|
86
|
+
tone: 'friendly and professional',
|
87
|
+
detail_level: 'detailed',
|
88
|
+
user_message: 'How do I implement a REST API in Ruby?'
|
92
89
|
)
|
93
90
|
|
94
|
-
puts
|
91
|
+
puts 'Compiled chat messages:'
|
95
92
|
compiled_messages.each_with_index do |message, index|
|
96
93
|
puts " #{index + 1}. #{message[:role]}: #{message[:content]}"
|
97
94
|
end
|
98
|
-
|
99
95
|
rescue Langfuse::APIError => e
|
100
96
|
puts "Could not retrieve chat prompt: #{e.message}"
|
101
97
|
end
|
@@ -112,34 +108,34 @@ puts "Template variables: #{translation_template.input_variables}"
|
|
112
108
|
|
113
109
|
# Use the template
|
114
110
|
translated_prompt = translation_template.format(
|
115
|
-
source_language:
|
116
|
-
target_language:
|
117
|
-
text:
|
111
|
+
source_language: 'English',
|
112
|
+
target_language: 'Spanish',
|
113
|
+
text: 'Hello, how are you today?'
|
118
114
|
)
|
119
115
|
|
120
116
|
puts "Translation prompt: #{translated_prompt}"
|
121
117
|
|
122
118
|
# Create a reusable chat template
|
123
119
|
coding_template = Langfuse::ChatPromptTemplate.from_messages([
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
])
|
120
|
+
{
|
121
|
+
role: 'system',
|
122
|
+
content: 'You are an expert {{language}} developer. Provide clean, well-commented code examples.'
|
123
|
+
},
|
124
|
+
{
|
125
|
+
role: 'user',
|
126
|
+
content: '{{request}}'
|
127
|
+
}
|
128
|
+
])
|
133
129
|
|
134
130
|
puts "Chat template variables: #{coding_template.input_variables}"
|
135
131
|
|
136
132
|
# Use the chat template
|
137
133
|
coding_messages = coding_template.format(
|
138
|
-
language:
|
139
|
-
request:
|
134
|
+
language: 'Ruby',
|
135
|
+
request: 'Show me how to create a simple HTTP server'
|
140
136
|
)
|
141
137
|
|
142
|
-
puts
|
138
|
+
puts 'Coding chat messages:'
|
143
139
|
coding_messages.each_with_index do |message, index|
|
144
140
|
puts " #{index + 1}. #{message[:role]}: #{message[:content]}"
|
145
141
|
end
|
@@ -149,17 +145,16 @@ puts "\n🔄 Example 4: Prompt versioning and caching"
|
|
149
145
|
|
150
146
|
# Get specific version of a prompt
|
151
147
|
begin
|
152
|
-
versioned_prompt = client.get_prompt(
|
148
|
+
versioned_prompt = client.get_prompt('greeting-prompt', version: 1)
|
153
149
|
puts "Retrieved prompt version: #{versioned_prompt.version}"
|
154
150
|
|
155
151
|
# Get latest version (cached)
|
156
|
-
latest_prompt = client.get_prompt(
|
152
|
+
latest_prompt = client.get_prompt('greeting-prompt')
|
157
153
|
puts "Latest prompt version: #{latest_prompt.version}"
|
158
154
|
|
159
155
|
# Get with label
|
160
|
-
labeled_prompt = client.get_prompt(
|
156
|
+
labeled_prompt = client.get_prompt('greeting-prompt', label: 'production')
|
161
157
|
puts "Labeled prompt: #{labeled_prompt.labels}"
|
162
|
-
|
163
158
|
rescue Langfuse::APIError => e
|
164
159
|
puts "Could not retrieve versioned prompt: #{e.message}"
|
165
160
|
end
|
@@ -169,27 +164,27 @@ puts "\n🔗 Example 5: Using prompts in tracing"
|
|
169
164
|
|
170
165
|
begin
|
171
166
|
# Get a prompt for use in generation
|
172
|
-
system_prompt = client.get_prompt(
|
167
|
+
system_prompt = client.get_prompt('ai-assistant-chat')
|
173
168
|
|
174
169
|
# Create a trace
|
175
170
|
trace = client.trace(
|
176
|
-
name:
|
177
|
-
user_id:
|
178
|
-
input: { message:
|
171
|
+
name: 'prompt-based-chat',
|
172
|
+
user_id: 'user-789',
|
173
|
+
input: { message: 'Explain Ruby blocks' }
|
179
174
|
)
|
180
175
|
|
181
176
|
# Compile the prompt
|
182
177
|
messages = system_prompt.compile(
|
183
|
-
domain:
|
184
|
-
tone:
|
185
|
-
detail_level:
|
186
|
-
user_message:
|
178
|
+
domain: 'Ruby programming',
|
179
|
+
tone: 'educational and clear',
|
180
|
+
detail_level: 'beginner-friendly',
|
181
|
+
user_message: 'Explain Ruby blocks'
|
187
182
|
)
|
188
183
|
|
189
184
|
# Create generation with prompt
|
190
185
|
generation = trace.generation(
|
191
|
-
name:
|
192
|
-
model:
|
186
|
+
name: 'openai-chat-with-prompt',
|
187
|
+
model: 'gpt-3.5-turbo',
|
193
188
|
input: messages,
|
194
189
|
output: {
|
195
190
|
content: "Ruby blocks are pieces of code that can be passed to methods. They're defined using either do...end or curly braces {}. Blocks are commonly used with iterators like .each, .map, and .select."
|
@@ -207,7 +202,6 @@ begin
|
|
207
202
|
|
208
203
|
puts "Created generation with prompt: #{generation.id}"
|
209
204
|
puts "Trace URL: #{trace.get_url}"
|
210
|
-
|
211
205
|
rescue Langfuse::APIError => e
|
212
206
|
puts "Could not use prompt in tracing: #{e.message}"
|
213
207
|
end
|
@@ -218,12 +212,12 @@ puts "\n🎯 Example 6: Advanced prompt features"
|
|
218
212
|
# Create a prompt with complex templating
|
219
213
|
begin
|
220
214
|
complex_prompt = client.create_prompt(
|
221
|
-
name:
|
215
|
+
name: 'code-review-prompt',
|
222
216
|
prompt: {
|
223
|
-
system:
|
217
|
+
system: 'You are a senior {{language}} developer reviewing code. Focus on {{review_aspects}}.',
|
224
218
|
user: "Please review this {{language}} code:\n\n```{{language}}\n{{code}}\n```\n\nProvide feedback on: {{specific_feedback}}"
|
225
219
|
},
|
226
|
-
labels: [
|
220
|
+
labels: %w[code-review development],
|
227
221
|
config: {
|
228
222
|
temperature: 0.3,
|
229
223
|
max_tokens: 500
|
@@ -231,7 +225,6 @@ begin
|
|
231
225
|
)
|
232
226
|
|
233
227
|
puts "Created complex prompt: #{complex_prompt.name}"
|
234
|
-
|
235
228
|
rescue Langfuse::APIError => e
|
236
229
|
puts "Note: Complex prompt might already exist - #{e.message}"
|
237
230
|
end
|
@@ -239,16 +232,14 @@ end
|
|
239
232
|
# Create a prompt with conditional logic (using Ruby)
|
240
233
|
class ConditionalPrompt
|
241
234
|
def self.generate(user_level:, topic:, include_examples: true)
|
242
|
-
base_prompt =
|
235
|
+
base_prompt = 'Explain {{topic}} for a {{user_level}} audience.'
|
243
236
|
|
244
|
-
if include_examples
|
245
|
-
base_prompt += " Include practical examples."
|
246
|
-
end
|
237
|
+
base_prompt += ' Include practical examples.' if include_examples
|
247
238
|
|
248
|
-
if user_level ==
|
249
|
-
base_prompt +=
|
250
|
-
elsif user_level ==
|
251
|
-
base_prompt +=
|
239
|
+
if user_level == 'beginner'
|
240
|
+
base_prompt += ' Use simple language and avoid jargon.'
|
241
|
+
elsif user_level == 'advanced'
|
242
|
+
base_prompt += ' Feel free to use technical terminology.'
|
252
243
|
end
|
253
244
|
|
254
245
|
base_prompt
|
@@ -256,8 +247,8 @@ class ConditionalPrompt
|
|
256
247
|
end
|
257
248
|
|
258
249
|
conditional_prompt_text = ConditionalPrompt.generate(
|
259
|
-
user_level:
|
260
|
-
topic:
|
250
|
+
user_level: 'beginner',
|
251
|
+
topic: 'machine learning',
|
261
252
|
include_examples: true
|
262
253
|
)
|
263
254
|
|
@@ -266,8 +257,8 @@ puts "Conditional prompt: #{conditional_prompt_text}"
|
|
266
257
|
# Use with template
|
267
258
|
conditional_template = Langfuse::PromptTemplate.from_template(conditional_prompt_text)
|
268
259
|
formatted_prompt = conditional_template.format(
|
269
|
-
topic:
|
270
|
-
user_level:
|
260
|
+
topic: 'neural networks',
|
261
|
+
user_level: 'beginner'
|
271
262
|
)
|
272
263
|
|
273
264
|
puts "Formatted conditional prompt: #{formatted_prompt}"
|
@@ -277,7 +268,7 @@ puts "\n🔄 Flushing events..."
|
|
277
268
|
client.flush
|
278
269
|
|
279
270
|
puts "\n✅ Prompt management example completed!"
|
280
|
-
puts
|
271
|
+
puts 'Check your Langfuse dashboard to see the prompts and traces.'
|
281
272
|
|
282
273
|
# Shutdown client
|
283
274
|
client.shutdown
|
data/lib/langfuse/client.rb
CHANGED
@@ -99,7 +99,7 @@ module Langfuse
|
|
99
99
|
return cached_prompt[:prompt]
|
100
100
|
end
|
101
101
|
|
102
|
-
path = "/api/public/prompts/#{name}"
|
102
|
+
path = "/api/public/v2/prompts/#{name}"
|
103
103
|
params = {}
|
104
104
|
params[:version] = version if version
|
105
105
|
params[:label] = label if label
|
@@ -138,7 +138,7 @@ module Langfuse
|
|
138
138
|
**kwargs
|
139
139
|
}
|
140
140
|
|
141
|
-
response = post('/api/public/prompts', data)
|
141
|
+
response = post('/api/public/v2/prompts', data)
|
142
142
|
Prompt.new(response.body)
|
143
143
|
end
|
144
144
|
|
@@ -227,15 +227,24 @@ module Langfuse
|
|
227
227
|
|
228
228
|
def build_connection
|
229
229
|
Faraday.new(url: @host) do |conn|
|
230
|
-
|
230
|
+
# 配置请求和响应处理
|
231
231
|
conn.request :json
|
232
|
-
# 更宽松的 JSON 响应处理,支持更多 content-type
|
233
232
|
conn.response :json, content_type: /\bjson$/
|
234
|
-
|
233
|
+
|
234
|
+
# 设置 User-Agent 头部
|
235
|
+
conn.headers['User-Agent'] = "langfuse-ruby/#{Langfuse::VERSION}"
|
236
|
+
# 根据 Langfuse 文档配置 Basic Auth
|
237
|
+
# username: Langfuse Public Key, password: Langfuse Secret Key
|
238
|
+
conn.headers['Authorization'] = "Basic #{Base64.strict_encode64("#{@public_key}:#{@secret_key}")}"
|
239
|
+
|
240
|
+
# 设置超时
|
235
241
|
conn.options.timeout = @timeout
|
236
242
|
|
237
|
-
#
|
243
|
+
# 添加调试日志
|
238
244
|
conn.response :logger if @debug
|
245
|
+
|
246
|
+
# 使用默认适配器
|
247
|
+
conn.adapter Faraday.default_adapter
|
239
248
|
end
|
240
249
|
end
|
241
250
|
|
data/lib/langfuse/version.rb
CHANGED
data/lib/langfuse.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Sun
|
@@ -175,19 +175,18 @@ files:
|
|
175
175
|
- ".github/workflows/ci.yml"
|
176
176
|
- ".github/workflows/release.yml"
|
177
177
|
- ".gitignore"
|
178
|
+
- CHANGELOG.md
|
178
179
|
- Gemfile
|
179
180
|
- Gemfile.lock
|
180
181
|
- LICENSE
|
181
|
-
- PROMPT_TROUBLESHOOTING.md
|
182
182
|
- README.md
|
183
183
|
- Rakefile
|
184
|
-
- docs/CHANGELOG.md
|
185
184
|
- docs/FINAL_SUMMARY.md
|
186
|
-
- docs/PROJECT_SUMMARY.md
|
187
185
|
- docs/PUBLISH_GUIDE.md
|
188
186
|
- docs/README.md
|
189
187
|
- docs/RELEASE_CHECKLIST.md
|
190
188
|
- examples/basic_tracing.rb
|
189
|
+
- examples/connection_config_demo.rb
|
191
190
|
- examples/prompt_management.rb
|
192
191
|
- langfuse-ruby.gemspec
|
193
192
|
- lib/langfuse.rb
|
@@ -202,7 +201,6 @@ files:
|
|
202
201
|
- lib/langfuse/version.rb
|
203
202
|
- scripts/release.sh
|
204
203
|
- scripts/verify_release.rb
|
205
|
-
- test_basic.rb
|
206
204
|
- test_offline.rb
|
207
205
|
homepage: https://langfuse.com
|
208
206
|
licenses:
|
data/PROMPT_TROUBLESHOOTING.md
DELETED
@@ -1,206 +0,0 @@
|
|
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/docs/CHANGELOG.md
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# Changelog
|
2
|
-
|
3
|
-
All notable changes to this project will be documented in this file.
|
4
|
-
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
-
|
8
|
-
## [Unreleased]
|
9
|
-
|
10
|
-
## [0.1.0] - 2025-01-09
|
11
|
-
|
12
|
-
### Added
|
13
|
-
- Initial release of Langfuse Ruby SDK
|
14
|
-
- Complete tracing functionality with traces, spans, and generations
|
15
|
-
- Prompt management with version control and caching
|
16
|
-
- Built-in evaluation system with multiple evaluators
|
17
|
-
- Comprehensive error handling and validation
|
18
|
-
- Automatic event batching and background processing
|
19
|
-
- Support for environment variable configuration
|
20
|
-
- Extensive documentation and examples
|
21
|
-
- Full test coverage with RSpec
|
22
|
-
- Framework integration examples (Rails, Sidekiq)
|
23
|
-
|
24
|
-
### Features
|
25
|
-
- **Tracing**: Create and manage traces with nested spans and generations
|
26
|
-
- **Prompt Management**: Create, retrieve, and compile prompts with variable substitution
|
27
|
-
- **Evaluation**: Built-in evaluators for exact match, similarity, length, regex, and custom scoring
|
28
|
-
- **Client Management**: Robust HTTP client with retries, timeouts, and authentication
|
29
|
-
- **Event Processing**: Asynchronous event queue with automatic flushing
|
30
|
-
- **Error Handling**: Comprehensive error types with detailed messages
|
31
|
-
- **Utilities**: Helper methods for ID generation, timestamps, and data transformation
|
32
|
-
|
33
|
-
### Dependencies
|
34
|
-
- faraday (~> 2.0) - HTTP client library
|
35
|
-
- faraday-net_http (~> 3.0) - Net::HTTP adapter for Faraday
|
36
|
-
- json (~> 2.0) - JSON parsing and generation
|
37
|
-
- concurrent-ruby (~> 1.0) - Thread-safe data structures
|
38
|
-
|
39
|
-
### Development Dependencies
|
40
|
-
- bundler (~> 2.0)
|
41
|
-
- rake (~> 13.0)
|
42
|
-
- rspec (~> 3.0)
|
43
|
-
- webmock (~> 3.0)
|
44
|
-
- vcr (~> 6.0)
|
45
|
-
- rubocop (~> 1.0)
|
46
|
-
- yard (~> 0.9)
|
47
|
-
|
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
|
data/docs/PROJECT_SUMMARY.md
DELETED
@@ -1,263 +0,0 @@
|
|
1
|
-
# Langfuse Ruby SDK - 项目总结
|
2
|
-
|
3
|
-
## 🎉 项目完成状态
|
4
|
-
|
5
|
-
✅ **项目已完成** - 所有核心功能已实现并通过测试
|
6
|
-
|
7
|
-
## 📋 功能清单
|
8
|
-
|
9
|
-
### ✅ 已实现的功能
|
10
|
-
|
11
|
-
1. **核心架构**
|
12
|
-
- [x] 模块化设计
|
13
|
-
- [x] 完整的错误处理系统
|
14
|
-
- [x] 配置管理
|
15
|
-
- [x] 工具类和辅助方法
|
16
|
-
|
17
|
-
2. **客户端管理**
|
18
|
-
- [x] HTTP 客户端(基于 Faraday)
|
19
|
-
- [x] 认证系统(Basic Auth)
|
20
|
-
- [x] 自动重试机制
|
21
|
-
- [x] 超时处理
|
22
|
-
- [x] 错误分类和处理
|
23
|
-
|
24
|
-
3. **追踪功能**
|
25
|
-
- [x] Trace 创建和管理
|
26
|
-
- [x] Span 创建和嵌套
|
27
|
-
- [x] Generation 追踪(LLM 调用)
|
28
|
-
- [x] 事件队列和批处理
|
29
|
-
- [x] 后台线程自动刷新
|
30
|
-
|
31
|
-
4. **提示管理**
|
32
|
-
- [x] 提示创建和获取
|
33
|
-
- [x] 版本控制
|
34
|
-
- [x] 缓存机制
|
35
|
-
- [x] 变量编译({{variable}} 格式)
|
36
|
-
- [x] 文本和聊天提示支持
|
37
|
-
- [x] 提示模板类
|
38
|
-
|
39
|
-
5. **评估系统**
|
40
|
-
- [x] 基础评估器框架
|
41
|
-
- [x] 精确匹配评估器
|
42
|
-
- [x] 相似度评估器(Levenshtein 距离)
|
43
|
-
- [x] 长度评估器
|
44
|
-
- [x] 包含评估器
|
45
|
-
- [x] 正则表达式评估器
|
46
|
-
- [x] 自定义评分系统
|
47
|
-
|
48
|
-
6. **测试和文档**
|
49
|
-
- [x] 完整的测试套件
|
50
|
-
- [x] 详细的 README 文档
|
51
|
-
- [x] 使用示例
|
52
|
-
- [x] API 文档
|
53
|
-
- [x] 变更日志
|
54
|
-
|
55
|
-
## 🏗️ 项目结构
|
56
|
-
|
57
|
-
```
|
58
|
-
langfuse/
|
59
|
-
├── lib/
|
60
|
-
│ └── langfuse/
|
61
|
-
│ ├── client.rb # 核心客户端
|
62
|
-
│ ├── trace.rb # 追踪功能
|
63
|
-
│ ├── span.rb # Span 管理
|
64
|
-
│ ├── generation.rb # Generation 管理
|
65
|
-
│ ├── prompt.rb # 提示管理
|
66
|
-
│ ├── evaluation.rb # 评估系统
|
67
|
-
│ ├── errors.rb # 错误定义
|
68
|
-
│ ├── utils.rb # 工具类
|
69
|
-
│ └── version.rb # 版本信息
|
70
|
-
├── spec/ # 测试文件
|
71
|
-
├── examples/ # 使用示例
|
72
|
-
├── langfuse.gemspec # Gem 规范
|
73
|
-
├── README.md # 项目文档
|
74
|
-
├── CHANGELOG.md # 变更日志
|
75
|
-
└── LICENSE # 许可证
|
76
|
-
```
|
77
|
-
|
78
|
-
## 🔧 技术栈
|
79
|
-
|
80
|
-
- **Ruby**: >= 2.7.0
|
81
|
-
- **HTTP 客户端**: Faraday 2.0+
|
82
|
-
- **并发处理**: concurrent-ruby 1.0+
|
83
|
-
- **JSON 处理**: json 2.0+
|
84
|
-
- **测试框架**: RSpec 3.0+
|
85
|
-
- **代码质量**: RuboCop 1.0+
|
86
|
-
|
87
|
-
## 🚀 核心特性
|
88
|
-
|
89
|
-
### 1. 追踪系统
|
90
|
-
- 支持嵌套的 traces、spans 和 generations
|
91
|
-
- 自动 ID 生成和时间戳
|
92
|
-
- 元数据和标签支持
|
93
|
-
- 异步事件处理
|
94
|
-
|
95
|
-
### 2. 提示管理
|
96
|
-
- 版本控制和缓存
|
97
|
-
- 变量替换系统
|
98
|
-
- 多种提示格式支持
|
99
|
-
- LangChain 兼容性
|
100
|
-
|
101
|
-
### 3. 评估框架
|
102
|
-
- 多种内置评估器
|
103
|
-
- 可扩展的评估系统
|
104
|
-
- 自定义评分支持
|
105
|
-
- 详细的评估结果
|
106
|
-
|
107
|
-
### 4. 企业级特性
|
108
|
-
- 完整的错误处理
|
109
|
-
- 配置管理
|
110
|
-
- 环境变量支持
|
111
|
-
- 框架集成示例
|
112
|
-
|
113
|
-
## 📊 测试结果
|
114
|
-
|
115
|
-
```
|
116
|
-
🚀 Testing Langfuse Ruby SDK (Offline Mode)...
|
117
|
-
|
118
|
-
✅ Configuration successful
|
119
|
-
✅ Client initialization successful
|
120
|
-
✅ Trace creation successful
|
121
|
-
✅ Generation creation successful
|
122
|
-
✅ Prompt template successful
|
123
|
-
✅ Chat prompt template successful
|
124
|
-
✅ Evaluators successful (5/5)
|
125
|
-
✅ Utils successful
|
126
|
-
✅ Event queue successful
|
127
|
-
✅ Complex workflow successful
|
128
|
-
✅ Error handling successful
|
129
|
-
|
130
|
-
🎉 All offline tests completed successfully!
|
131
|
-
```
|
132
|
-
|
133
|
-
## 📚 使用示例
|
134
|
-
|
135
|
-
### 基本用法
|
136
|
-
```ruby
|
137
|
-
require 'langfuse'
|
138
|
-
|
139
|
-
client = Langfuse.new(
|
140
|
-
public_key: "pk-lf-...",
|
141
|
-
secret_key: "sk-lf-..."
|
142
|
-
)
|
143
|
-
|
144
|
-
trace = client.trace(
|
145
|
-
name: "chat-completion",
|
146
|
-
user_id: "user123",
|
147
|
-
input: { message: "Hello!" }
|
148
|
-
)
|
149
|
-
|
150
|
-
generation = trace.generation(
|
151
|
-
name: "openai-chat",
|
152
|
-
model: "gpt-3.5-turbo",
|
153
|
-
input: [{ role: "user", content: "Hello!" }],
|
154
|
-
output: { content: "Hi there!" }
|
155
|
-
)
|
156
|
-
|
157
|
-
client.flush
|
158
|
-
```
|
159
|
-
|
160
|
-
### 提示管理
|
161
|
-
```ruby
|
162
|
-
# 获取提示
|
163
|
-
prompt = client.get_prompt("greeting-prompt")
|
164
|
-
|
165
|
-
# 编译提示
|
166
|
-
compiled = prompt.compile(
|
167
|
-
user_name: "Alice",
|
168
|
-
topic: "AI"
|
169
|
-
)
|
170
|
-
```
|
171
|
-
|
172
|
-
### 评估系统
|
173
|
-
```ruby
|
174
|
-
evaluator = Langfuse::Evaluators::ExactMatchEvaluator.new
|
175
|
-
result = evaluator.evaluate(
|
176
|
-
"What is 2+2?",
|
177
|
-
"4",
|
178
|
-
expected: "4"
|
179
|
-
)
|
180
|
-
```
|
181
|
-
|
182
|
-
## 🔄 与官方 SDK 对比
|
183
|
-
|
184
|
-
| 功能 | Python SDK | JS SDK | Ruby SDK |
|
185
|
-
|------|------------|--------|----------|
|
186
|
-
| 基础追踪 | ✅ | ✅ | ✅ |
|
187
|
-
| 提示管理 | ✅ | ✅ | ✅ |
|
188
|
-
| 评估系统 | ✅ | ✅ | ✅ |
|
189
|
-
| 异步处理 | ✅ | ✅ | ✅ |
|
190
|
-
| 错误处理 | ✅ | ✅ | ✅ |
|
191
|
-
| 框架集成 | ✅ | ✅ | ✅ |
|
192
|
-
|
193
|
-
## 📦 发布准备
|
194
|
-
|
195
|
-
### Gem 规范
|
196
|
-
- 名称: `langfuse`
|
197
|
-
- 版本: `0.1.0`
|
198
|
-
- 许可证: MIT
|
199
|
-
- Ruby 版本: >= 2.7.0
|
200
|
-
|
201
|
-
### 依赖项
|
202
|
-
```ruby
|
203
|
-
spec.add_dependency "faraday", "~> 2.0"
|
204
|
-
spec.add_dependency "faraday-net_http", "~> 3.0"
|
205
|
-
spec.add_dependency "json", "~> 2.0"
|
206
|
-
spec.add_dependency "concurrent-ruby", "~> 1.0"
|
207
|
-
```
|
208
|
-
|
209
|
-
## 🛠️ 开发指南
|
210
|
-
|
211
|
-
### 安装依赖
|
212
|
-
```bash
|
213
|
-
bundle install
|
214
|
-
```
|
215
|
-
|
216
|
-
### 运行测试
|
217
|
-
```bash
|
218
|
-
bundle exec rspec
|
219
|
-
```
|
220
|
-
|
221
|
-
### 离线测试
|
222
|
-
```bash
|
223
|
-
ruby test_offline.rb
|
224
|
-
```
|
225
|
-
|
226
|
-
## 🔮 未来扩展
|
227
|
-
|
228
|
-
### 可能的改进
|
229
|
-
1. **性能优化**
|
230
|
-
- 连接池管理
|
231
|
-
- 更高效的批处理
|
232
|
-
- 内存优化
|
233
|
-
|
234
|
-
2. **功能扩展**
|
235
|
-
- 更多评估器
|
236
|
-
- 数据集管理
|
237
|
-
- 实验功能
|
238
|
-
|
239
|
-
3. **集成支持**
|
240
|
-
- Rails 集成 gem
|
241
|
-
- Sidekiq 中间件
|
242
|
-
- 更多框架支持
|
243
|
-
|
244
|
-
## 📄 许可证
|
245
|
-
|
246
|
-
MIT License - 允许商业和开源使用
|
247
|
-
|
248
|
-
## 🤝 贡献指南
|
249
|
-
|
250
|
-
1. Fork 项目
|
251
|
-
2. 创建功能分支
|
252
|
-
3. 提交更改
|
253
|
-
4. 创建 Pull Request
|
254
|
-
|
255
|
-
## 📞 支持
|
256
|
-
|
257
|
-
- GitHub Issues: 报告 bug 和功能请求
|
258
|
-
- 文档: 详细的使用指南
|
259
|
-
- 示例: 完整的使用示例
|
260
|
-
|
261
|
-
---
|
262
|
-
|
263
|
-
**总结**: 这个 Langfuse Ruby SDK 是一个功能完整、测试充分的生产级 SDK,完全兼容 Langfuse API,可以立即用于生产环境。它提供了与官方 Python 和 JavaScript SDK 相同的功能,并且遵循 Ruby 社区的最佳实践。
|
data/test_basic.rb
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require_relative 'lib/langfuse'
|
4
|
-
|
5
|
-
puts "🚀 Testing Langfuse Ruby SDK..."
|
6
|
-
|
7
|
-
# Test 1: Basic configuration
|
8
|
-
puts "\n1. Testing configuration..."
|
9
|
-
Langfuse.configure do |config|
|
10
|
-
config.public_key = "test_key"
|
11
|
-
config.secret_key = "test_secret"
|
12
|
-
config.host = "https://test.langfuse.com"
|
13
|
-
config.debug = true
|
14
|
-
end
|
15
|
-
|
16
|
-
puts "✅ Configuration successful"
|
17
|
-
puts " Public key: #{Langfuse.configuration.public_key}"
|
18
|
-
puts " Host: #{Langfuse.configuration.host}"
|
19
|
-
|
20
|
-
# Test 2: Client initialization
|
21
|
-
puts "\n2. Testing client initialization..."
|
22
|
-
begin
|
23
|
-
client = Langfuse.new(
|
24
|
-
public_key: "test_key",
|
25
|
-
secret_key: "test_secret",
|
26
|
-
host: "https://test.langfuse.com"
|
27
|
-
)
|
28
|
-
puts "✅ Client initialization successful"
|
29
|
-
puts " Client class: #{client.class}"
|
30
|
-
puts " Public key: #{client.public_key}"
|
31
|
-
rescue => e
|
32
|
-
puts "❌ Client initialization failed: #{e.message}"
|
33
|
-
end
|
34
|
-
|
35
|
-
# Test 3: Trace creation
|
36
|
-
puts "\n3. Testing trace creation..."
|
37
|
-
begin
|
38
|
-
trace = client.trace(
|
39
|
-
name: "test-trace",
|
40
|
-
user_id: "test-user",
|
41
|
-
input: { message: "Hello, world!" }
|
42
|
-
)
|
43
|
-
puts "✅ Trace creation successful"
|
44
|
-
puts " Trace ID: #{trace.id}"
|
45
|
-
puts " Trace name: #{trace.name}"
|
46
|
-
rescue => e
|
47
|
-
puts "❌ Trace creation failed: #{e.message}"
|
48
|
-
end
|
49
|
-
|
50
|
-
# Test 4: Generation creation
|
51
|
-
puts "\n4. Testing generation creation..."
|
52
|
-
begin
|
53
|
-
generation = trace.generation(
|
54
|
-
name: "test-generation",
|
55
|
-
model: "gpt-3.5-turbo",
|
56
|
-
input: [{ role: "user", content: "Hello!" }],
|
57
|
-
output: { content: "Hi there!" }
|
58
|
-
)
|
59
|
-
puts "✅ Generation creation successful"
|
60
|
-
puts " Generation ID: #{generation.id}"
|
61
|
-
puts " Model: #{generation.model}"
|
62
|
-
rescue => e
|
63
|
-
puts "❌ Generation creation failed: #{e.message}"
|
64
|
-
end
|
65
|
-
|
66
|
-
# Test 5: Span creation
|
67
|
-
puts "\n5. Testing span creation..."
|
68
|
-
begin
|
69
|
-
span = trace.span(
|
70
|
-
name: "test-span",
|
71
|
-
input: { query: "test query" }
|
72
|
-
)
|
73
|
-
puts "✅ Span creation successful"
|
74
|
-
puts " Span ID: #{span.id}"
|
75
|
-
puts " Span name: #{span.name}"
|
76
|
-
rescue => e
|
77
|
-
puts "❌ Span creation failed: #{e.message}"
|
78
|
-
end
|
79
|
-
|
80
|
-
# Test 6: Prompt template
|
81
|
-
puts "\n6. Testing prompt template..."
|
82
|
-
begin
|
83
|
-
template = Langfuse::PromptTemplate.from_template(
|
84
|
-
"Hello {{name}}! How are you feeling {{mood}} today?"
|
85
|
-
)
|
86
|
-
|
87
|
-
formatted = template.format(
|
88
|
-
name: "Alice",
|
89
|
-
mood: "happy"
|
90
|
-
)
|
91
|
-
|
92
|
-
puts "✅ Prompt template successful"
|
93
|
-
puts " Template variables: #{template.input_variables}"
|
94
|
-
puts " Formatted: #{formatted}"
|
95
|
-
rescue => e
|
96
|
-
puts "❌ Prompt template failed: #{e.message}"
|
97
|
-
end
|
98
|
-
|
99
|
-
# Test 7: Chat prompt template
|
100
|
-
puts "\n7. Testing chat prompt template..."
|
101
|
-
begin
|
102
|
-
chat_template = Langfuse::ChatPromptTemplate.from_messages([
|
103
|
-
{ role: "system", content: "You are a helpful {{role}} assistant." },
|
104
|
-
{ role: "user", content: "{{user_input}}" }
|
105
|
-
])
|
106
|
-
|
107
|
-
messages = chat_template.format(
|
108
|
-
role: "coding",
|
109
|
-
user_input: "Help me with Ruby"
|
110
|
-
)
|
111
|
-
|
112
|
-
puts "✅ Chat prompt template successful"
|
113
|
-
puts " Template variables: #{chat_template.input_variables}"
|
114
|
-
puts " Messages count: #{messages.length}"
|
115
|
-
rescue => e
|
116
|
-
puts "❌ Chat prompt template failed: #{e.message}"
|
117
|
-
end
|
118
|
-
|
119
|
-
# Test 8: Evaluators
|
120
|
-
puts "\n8. Testing evaluators..."
|
121
|
-
begin
|
122
|
-
# Exact match evaluator
|
123
|
-
exact_match = Langfuse::Evaluators::ExactMatchEvaluator.new
|
124
|
-
result = exact_match.evaluate(
|
125
|
-
input: "What is 2+2?",
|
126
|
-
output: "4",
|
127
|
-
expected: "4"
|
128
|
-
)
|
129
|
-
puts "✅ Exact match evaluator successful"
|
130
|
-
puts " Result: #{result}"
|
131
|
-
|
132
|
-
# Similarity evaluator
|
133
|
-
similarity = Langfuse::Evaluators::SimilarityEvaluator.new
|
134
|
-
result = similarity.evaluate(
|
135
|
-
input: "What is AI?",
|
136
|
-
output: "Artificial Intelligence",
|
137
|
-
expected: "AI is artificial intelligence"
|
138
|
-
)
|
139
|
-
puts "✅ Similarity evaluator successful"
|
140
|
-
puts " Result: #{result}"
|
141
|
-
rescue => e
|
142
|
-
puts "❌ Evaluator failed: #{e.message}"
|
143
|
-
end
|
144
|
-
|
145
|
-
# Test 9: Utils
|
146
|
-
puts "\n9. Testing utilities..."
|
147
|
-
begin
|
148
|
-
id = Langfuse::Utils.generate_id
|
149
|
-
timestamp = Langfuse::Utils.current_timestamp
|
150
|
-
|
151
|
-
puts "✅ Utils successful"
|
152
|
-
puts " Generated ID: #{id}"
|
153
|
-
puts " Timestamp: #{timestamp}"
|
154
|
-
rescue => e
|
155
|
-
puts "❌ Utils failed: #{e.message}"
|
156
|
-
end
|
157
|
-
|
158
|
-
# Test 10: Event queue
|
159
|
-
puts "\n10. Testing event queue..."
|
160
|
-
begin
|
161
|
-
queue_size_before = client.instance_variable_get(:@event_queue).length
|
162
|
-
|
163
|
-
client.score(
|
164
|
-
trace_id: trace.id,
|
165
|
-
name: "test-score",
|
166
|
-
value: 0.9
|
167
|
-
)
|
168
|
-
|
169
|
-
queue_size_after = client.instance_variable_get(:@event_queue).length
|
170
|
-
|
171
|
-
puts "✅ Event queue successful"
|
172
|
-
puts " Queue size before: #{queue_size_before}"
|
173
|
-
puts " Queue size after: #{queue_size_after}"
|
174
|
-
rescue => e
|
175
|
-
puts "❌ Event queue failed: #{e.message}"
|
176
|
-
end
|
177
|
-
|
178
|
-
puts "\n🎉 All tests completed!"
|
179
|
-
puts " This SDK is ready for use with Langfuse!"
|
180
|
-
puts " Remember to set your real API keys when using in production."
|
181
|
-
|
182
|
-
# Clean shutdown
|
183
|
-
client.shutdown
|