genkit icon indicating copy to clipboard operation
genkit copied to clipboard

fix: add span for prompt template rendering

Open MichaelDoyle opened this issue 10 months ago • 7 comments

Fixes #2064

image image

Checklist (if applicable):

  • [x] PR title is following https://www.conventionalcommits.org/en/v1.0.0/
  • [x] Tested (manually, unit tested, etc.)
  • [x] Docs updated (updated docs or a docs bug required)

MichaelDoyle avatar Feb 25 '25 03:02 MichaelDoyle

Can you share the code snippet that produces the trace in the screenshot?

pavelgj avatar Feb 25 '25 14:02 pavelgj

hello.history.prompt

---
model: googleai/gemini-1.5-flash
config:
  maxOutputTokens: 2048
  temperature: 0.6
  topK: 16
  topP: 0.95
  safetySettings:
    - category: HARM_CATEGORY_HATE_SPEECH
      threshold: BLOCK_ONLY_HIGH
    - category: HARM_CATEGORY_DANGEROUS_CONTENT
      threshold: BLOCK_ONLY_HIGH
    - category: HARM_CATEGORY_HARASSMENT
      threshold: BLOCK_ONLY_HIGH
    - category: HARM_CATEGORY_SEXUALLY_EXPLICIT
      threshold: BLOCK_ONLY_HIGH
input:
  schema:
    name: string
    persona?: string
  default:
    persona: Space Pirate
---

{{role "system"}}
You are a helpful AI assistant that really loves to make impressions.
{{role "user"}}
Say hello to Michael in the voice of a Space Pirate.
{{role "model"}}
Shiver me timbers, matey! We be sailing the solar winds!
{{role "user"}}
Say hello to {{name}} in the voice of a {{persona}}.

flowDotPromptHistory

export const HelloSchema = z.object({
  name: z.string(),
  persona: z.string().optional(),
});

ai.defineFlow(
  {
    name: 'flowDotPromptHistory',
    inputSchema: HelloSchema,
    outputSchema: z.any(),
  },
  async (input) => {
    const hello = ai.prompt('hello', {
      variant: 'history',
    });
    return (await hello(input)).text;
  }
);

MichaelDoyle avatar Feb 25 '25 14:02 MichaelDoyle

hello.history.prompt

---
model: googleai/gemini-1.5-flash
config:
  maxOutputTokens: 2048
  temperature: 0.6
  topK: 16
  topP: 0.95
  safetySettings:
    - category: HARM_CATEGORY_HATE_SPEECH
      threshold: BLOCK_ONLY_HIGH
    - category: HARM_CATEGORY_DANGEROUS_CONTENT
      threshold: BLOCK_ONLY_HIGH
    - category: HARM_CATEGORY_HARASSMENT
      threshold: BLOCK_ONLY_HIGH
    - category: HARM_CATEGORY_SEXUALLY_EXPLICIT
      threshold: BLOCK_ONLY_HIGH
input:
  schema:
    name: string
    persona?: string
  default:
    persona: Space Pirate
---

{{role "system"}}
You are a helpful AI assistant that really loves to make impressions.
{{role "user"}}
Say hello to Michael in the voice of a Space Pirate.
{{role "model"}}
Shiver me timbers, matey! We be sailing the solar winds!
{{role "user"}}
Say hello to {{name}} in the voice of a {{persona}}.

flowDotPromptHistory

export const HelloSchema = z.object({
  name: z.string(),
  persona: z.string().optional(),
});

ai.defineFlow(
  {
    name: 'flowDotPromptHistory',
    inputSchema: HelloSchema,
    outputSchema: z.any(),
  },
  async (input) => {
    const hello = ai.prompt('hello', {
      variant: 'history',
    });
    return (await hello(input)).text;
  }
);

So, what I'm thinking is that perhaps the traces should look something like this:

hello.history
  |- render
  |- generate
    |- googleai/gemini-1.5-flash

os do you think it would get too verbose? extra span with redundant info?

Semi-related: I was also chatting with Shruti yesterday... I think we should change render to return GenereateActionOptions instead of GenerateRequest....

pavelgj avatar Feb 26 '25 14:02 pavelgj

I think that's the right approach. Been swept up in some other things, but will try and knock this out today.

MichaelDoyle avatar Feb 28 '25 13:02 MichaelDoyle

@pavelgj I got this going for the generate case. I wasn't exactly sure what to do for prompt.stream(), though, since generateStreaming is sync while runInNewSpan returns a Promise.

MichaelDoyle avatar Mar 01 '25 19:03 MichaelDoyle

@pavelgj I got this going for the generate case. I wasn't exactly sure what to do for prompt.stream(), though, since generateStreaming is sync while runInNewSpan returns a Promise.

I swear I replied to this.... sigh....

One thing I can think of is to use the Channel approach used in generateStream to wrap it manually:

https://github.com/firebase/genkit/blob/238b656736b9b4832d27337867b2441776f5836c/js/ai/src/generate.ts#L466

pavelgj avatar Mar 11 '25 14:03 pavelgj

@schnecle same applies to the generate util as well, correct? maybe we should do a separate pass on metrics. I think theres a couple things there.

MichaelDoyle avatar May 07 '25 02:05 MichaelDoyle