Skip to content

Commit 5c9d6ee

Browse files
authored
feat: add transID for ai function (#817)
# Description Add transID for ai function, each request will have an unique transID, and we can use `FromTransIDContext` to retrieve it from the `ctx`.
1 parent b477013 commit 5c9d6ee

3 files changed

Lines changed: 53 additions & 39 deletions

File tree

ai/model.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ type OverviewResponse struct {
1515

1616
// InvokeRequest is the request from user to BasicAPIServer
1717
type InvokeRequest struct {
18-
ReqID string `json:"req_id"` // ReqID is the request id of the request
1918
Prompt string `json:"prompt"` // Prompt is user input text for chat completion
2019
IncludeCallStack bool `json:"include_call_stack"` // IncludeCallStack is the flag to include call stack in response
2120
}

pkg/bridge/ai/api_server.go

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import (
99
"net/http"
1010
"time"
1111

12-
gonanoid "github.com/matoous/go-nanoid/v2"
1312
openai "github.com/sashabaranov/go-openai"
1413
"github.com/yomorun/yomo/ai"
1514
"github.com/yomorun/yomo/core/ylog"
15+
"github.com/yomorun/yomo/pkg/id"
1616
)
1717

1818
const (
@@ -97,7 +97,10 @@ func WithContextService(handler http.Handler, credential string, zipperAddr stri
9797
}
9898

9999
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
100-
handler.ServeHTTP(w, r.WithContext(WithServiceContext(r.Context(), service)))
100+
transID := id.New(32)
101+
ctx := WithTransIDContext(r.Context(), transID)
102+
ctx = WithServiceContext(ctx, service)
103+
handler.ServeHTTP(w, r.WithContext(ctx))
101104
})
102105
}
103106

@@ -119,18 +122,14 @@ func HandleOverview(w http.ResponseWriter, r *http.Request) {
119122

120123
// HandleInvoke is the handler for POST /invoke
121124
func HandleInvoke(w http.ResponseWriter, r *http.Request) {
122-
service := FromServiceContext(r.Context())
125+
var (
126+
ctx = r.Context()
127+
service = FromServiceContext(ctx)
128+
transID = FromTransIDContext(ctx)
129+
)
123130
defer r.Body.Close()
124-
reqID, err := gonanoid.New(6)
125-
if err != nil {
126-
ylog.Error("generate reqID", "err", err.Error())
127-
w.WriteHeader(http.StatusInternalServerError)
128-
json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
129-
return
130-
}
131131

132132
var req ai.InvokeRequest
133-
req.ReqID = reqID
134133

135134
// decode the request
136135
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -154,8 +153,8 @@ func HandleInvoke(w http.ResponseWriter, r *http.Request) {
154153
errCh := make(chan error, 1)
155154
go func(service *Service, req ai.InvokeRequest, baseSystemMessage string) {
156155
// call llm to infer the function and arguments to be invoked
157-
ylog.Debug(">> ai request", "reqID", req.ReqID, "prompt", req.Prompt)
158-
res, err := service.GetInvoke(ctx, req.Prompt, baseSystemMessage, req.ReqID, req.IncludeCallStack)
156+
ylog.Debug(">> ai request", "transID", transID, "prompt", req.Prompt)
157+
res, err := service.GetInvoke(ctx, req.Prompt, baseSystemMessage, transID, req.IncludeCallStack)
159158
if err != nil {
160159
errCh <- err
161160
} else {
@@ -183,16 +182,13 @@ func HandleInvoke(w http.ResponseWriter, r *http.Request) {
183182

184183
// HandleChatCompletions is the handler for POST /chat/completion
185184
func HandleChatCompletions(w http.ResponseWriter, r *http.Request) {
186-
service := FromServiceContext(r.Context())
185+
var (
186+
ctx = r.Context()
187+
service = FromServiceContext(ctx)
188+
transID = FromTransIDContext(ctx)
189+
)
187190
defer r.Body.Close()
188191

189-
reqID, err := gonanoid.New(6)
190-
if err != nil {
191-
ylog.Error("generate reqID", "err", err.Error())
192-
RespondWithError(w, http.StatusInternalServerError, err)
193-
return
194-
}
195-
196192
var req openai.ChatCompletionRequest
197193
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
198194
ylog.Error("decode request", "err", err.Error())
@@ -203,7 +199,7 @@ func HandleChatCompletions(w http.ResponseWriter, r *http.Request) {
203199
ctx, cancel := context.WithTimeout(r.Context(), 90*time.Second)
204200
defer cancel()
205201

206-
if err := service.GetChatCompletions(ctx, req, reqID, w, false); err != nil {
202+
if err := service.GetChatCompletions(ctx, req, transID, w, false); err != nil {
207203
ylog.Error("invoke chat completions", "err", err.Error())
208204
RespondWithError(w, http.StatusBadRequest, err)
209205
return
@@ -248,3 +244,19 @@ func FromServiceContext(ctx context.Context) *Service {
248244
}
249245
return service
250246
}
247+
248+
type transIDContextKey struct{}
249+
250+
// WithTransIDContext adds the transID to the request context
251+
func WithTransIDContext(ctx context.Context, transID string) context.Context {
252+
return context.WithValue(ctx, transIDContextKey{}, transID)
253+
}
254+
255+
// FromTransIDContext returns the transID from the request context
256+
func FromTransIDContext(ctx context.Context) string {
257+
val, ok := ctx.Value(transIDContextKey{}).(string)
258+
if !ok {
259+
return ""
260+
}
261+
return val
262+
}

pkg/bridge/ai/service.go

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/yomorun/yomo/core/metadata"
1919
"github.com/yomorun/yomo/core/ylog"
2020
"github.com/yomorun/yomo/pkg/bridge/ai/register"
21+
"github.com/yomorun/yomo/pkg/id"
2122
"github.com/yomorun/yomo/serverless"
2223
)
2324

@@ -164,7 +165,7 @@ func (s *Service) createReducer() (yomo.StreamFunction, error) {
164165
c, ok := s.sfnCallCache[reqID]
165166
s.muCallCache.Unlock()
166167
if !ok {
167-
ylog.Error("[sfn-reducer] req_id not found", "req_id", reqID)
168+
ylog.Error("[sfn-reducer] req_id not found", "trans_id", invoke.TransID, "req_id", reqID)
168169
return
169170
}
170171

@@ -204,7 +205,7 @@ func (s *Service) GetOverview() (*ai.OverviewResponse, error) {
204205
}
205206

206207
// GetInvoke returns the invoke response
207-
func (s *Service) GetInvoke(ctx context.Context, userInstruction string, baseSystemMessage string, reqID string, includeCallStack bool) (*ai.InvokeResponse, error) {
208+
func (s *Service) GetInvoke(ctx context.Context, userInstruction string, baseSystemMessage string, transID string, includeCallStack bool) (*ai.InvokeResponse, error) {
208209
// read tools attached to the metadata
209210
tcs, err := register.ListToolCalls(s.Metadata)
210211
if err != nil {
@@ -243,8 +244,8 @@ func (s *Service) GetInvoke(ctx context.Context, userInstruction string, baseSys
243244
"res_toolcalls", fmt.Sprintf("%+v", res.ToolCalls),
244245
"res_assistant_msgs", fmt.Sprintf("%+v", res.AssistantMessage))
245246

246-
ylog.Debug(">> run function calls", "reqID", reqID, "res.ToolCalls", fmt.Sprintf("%+v", res.ToolCalls))
247-
llmCalls, err := s.runFunctionCalls(res.ToolCalls, reqID)
247+
ylog.Debug(">> run function calls", "transID", transID, "res.ToolCalls", fmt.Sprintf("%+v", res.ToolCalls))
248+
llmCalls, err := s.runFunctionCalls(res.ToolCalls, transID, id.New(16))
248249
if err != nil {
249250
return nil, err
250251
}
@@ -322,7 +323,7 @@ func overWriteSystemPrompt(req openai.ChatCompletionRequest, sysPrompt string) o
322323
}
323324

324325
// GetChatCompletions returns the llm api response
325-
func (s *Service) GetChatCompletions(ctx context.Context, req openai.ChatCompletionRequest, reqID string, w http.ResponseWriter, includeCallStack bool) error {
326+
func (s *Service) GetChatCompletions(ctx context.Context, req openai.ChatCompletionRequest, transID string, w http.ResponseWriter, includeCallStack bool) error {
326327
// 1. find all hosting tool sfn
327328
tagTools, err := register.ListToolCalls(s.Metadata)
328329
if err != nil {
@@ -386,7 +387,7 @@ func (s *Service) GetChatCompletions(ctx context.Context, req openai.ChatComplet
386387
toolCallsMap[index] = item
387388
}
388389
isFunctionCall = true
389-
} else {
390+
} else if streamRes.Choices[0].FinishReason != openai.FinishReasonToolCalls {
390391
_, _ = io.WriteString(w, "data: ")
391392
_ = json.NewEncoder(w).Encode(streamRes)
392393
_, _ = io.WriteString(w, "\n")
@@ -436,7 +437,8 @@ func (s *Service) GetChatCompletions(ctx context.Context, req openai.ChatComplet
436437
}
437438
}
438439
// 6. run llm function calls
439-
llmCalls, err := s.runFunctionCalls(fnCalls, reqID)
440+
reqID := id.New(16)
441+
llmCalls, err := s.runFunctionCalls(fnCalls, transID, reqID)
440442
if err != nil {
441443
return err
442444
}
@@ -471,9 +473,6 @@ func (s *Service) GetChatCompletions(ctx context.Context, req openai.ChatComplet
471473
if err != nil {
472474
return err
473475
}
474-
if len(streamRes.Choices) == 0 {
475-
continue
476-
}
477476
_, _ = io.WriteString(w, "data: ")
478477
_ = json.NewEncoder(w).Encode(streamRes)
479478
_, _ = io.WriteString(w, "\n")
@@ -491,22 +490,23 @@ func (s *Service) GetChatCompletions(ctx context.Context, req openai.ChatComplet
491490
}
492491

493492
// run llm-sfn function calls
494-
func (s *Service) runFunctionCalls(fns map[uint32][]*openai.ToolCall, reqID string) ([]ai.ToolMessage, error) {
493+
func (s *Service) runFunctionCalls(fns map[uint32][]*openai.ToolCall, transID, reqID string) ([]ai.ToolMessage, error) {
495494
if len(fns) == 0 {
496495
return nil, nil
497496
}
498497

499498
asyncCall := &sfnAsyncCall{
500499
val: make(map[string]ai.ToolMessage),
501500
}
501+
502502
s.muCallCache.Lock()
503503
s.sfnCallCache[reqID] = asyncCall
504504
s.muCallCache.Unlock()
505505

506506
for tag, tcs := range fns {
507-
ylog.Debug("+++invoke toolCalls", "tag", tag, "len(toolCalls)", len(tcs), "reqID", reqID)
507+
ylog.Debug("+++invoke toolCalls", "tag", tag, "len(toolCalls)", len(tcs), "transID", transID, "reqID", reqID)
508508
for _, fn := range tcs {
509-
err := s.fireLlmSfn(tag, fn, reqID)
509+
err := s.fireLlmSfn(tag, fn, transID, reqID)
510510
if err != nil {
511511
ylog.Error("send data to zipper", "err", err.Error())
512512
continue
@@ -533,19 +533,22 @@ func (s *Service) runFunctionCalls(fns map[uint32][]*openai.ToolCall, reqID stri
533533
}
534534

535535
// fireLlmSfn fires the llm-sfn function call by s.source.Write()
536-
func (s *Service) fireLlmSfn(tag uint32, fn *openai.ToolCall, reqID string) error {
536+
func (s *Service) fireLlmSfn(tag uint32, fn *openai.ToolCall, transID, reqID string) error {
537537
ylog.Info(
538538
"+invoke func",
539539
"tag", tag,
540+
"transID", transID,
541+
"reqID", reqID,
540542
"toolCallID", fn.ID,
541543
"function", fn.Function.Name,
542544
"arguments", fn.Function.Arguments,
543-
"reqID", reqID)
545+
)
544546
data := &ai.FunctionCall{
547+
TransID: transID,
545548
ReqID: reqID,
546549
ToolCallID: fn.ID,
547-
Arguments: fn.Function.Arguments,
548550
FunctionName: fn.Function.Name,
551+
Arguments: fn.Function.Arguments,
549552
}
550553
buf, err := data.Bytes()
551554
if err != nil {

0 commit comments

Comments
 (0)